[
  {
    "path": ".github/ISSUE_TEMPLATE/------.md",
    "content": "---\nname: 规约问题模板\nabout: 规约问题请使用该模板\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n## 规约原文\n\n## 问题描述\n\n## 修改建议\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/rule-issue-template.md",
    "content": "---\nname: Rule issue template\nabout: Rule issue please use this template.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n## Rule content\n\n## Problem description\n\n## Advice\n"
  },
  {
    "path": ".gitignore",
    "content": "# Gradle\nbuild\n.gradle\n\ntestdata/\n# Java gitignore #\n.class\n.log\n\n# Package Files #\n\n*.war\n*.ear\n\n#hsf files\nconfiguration\n\n# maven gitignore#\ntarget/**\n\n.svn/\n\n# intelliJ.gitignore #\n.idea\n*.iml\n*.ipr\n*.iws\n\n\n# Eclipse git ignore#\n*.pydevproject\n.project\n.metadata\nbin/**\n*/bin/**\ntmp/**\ntmp/**/*\nconfiguration/**\n*.tmp\n*.bak\n*.orig\n*.swp\n*~.nib\n.classpath\n.settings/\n.loadpath\n.fileTable*\n.cache\n\n# External tool builders\n.externalToolBuilders/\n\n# Locally stored \"Eclipse launch configurations\"\n*.launch\n\n# CDT-specific\n.cproject\n\n# PDT-specific\n.buildpath\n\n#log\n*.log\n*.log.*\n\n# Windows Thumbs.db\n*.db\n\n# OSX\n.DS_Store\n\n# sass gitignore#\n.sass-cache\n.idea\n\n# tcc_coverage\ncoverage.ec\n\n\n\nconfig.client.*\n\ntemp/\n*.pid\n*.orig\n\nhsf.configuration/\n\n# code coverage report\n*.ec\n\n#hsf test\n*.instance\nout\n!/p3c-idea/src/main/kotlin/com/alibaba/smartfox/work/tools/aone/ui/AoneBranchView.kt\n"
  },
  {
    "path": "README.md",
    "content": "# P3C\n\n最新版本：黄山版（2022.2.3发布）\n\n[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\n## <font color=\"green\">Preface</font>\n> We are pleased to present Alibaba Java Coding Guidelines which consolidates the best programming practices over the years from Alibaba Group's technical teams. A vast number of Java programming teams impose demanding requirements on code quality across projects as we encourage reuse and better understanding of each other's programs. We have seen many programming problems in the past. For example, defective database table structures and index designs may cause software architecture flaws and performance risks. Another example is confusing code structures being difficult to maintain. Furthermore, vulnerable code without authentication is prone to hackers’ attacks. To address these kinds of problems, we developed this document for Java developers at Alibaba.\n \nFor more information please refer the *Alibaba Java Coding Guidelines*:\n- 中文版: 直接下载上方的PDF文件（黄山版）\n- English Version: *[Alibaba Java Coding Guidelines](https://alibaba.github.io/Alibaba-Java-Coding-Guidelines)*\n\n## <font color=\"green\">Introduction</font>\nThe project consists of 3 parts:  \n- [PMD implementations](p3c-pmd)  \n- [IntelliJ IDEA plugin](idea-plugin)  \n- [Eclipse plugin](eclipse-plugin)   \n\n## <font color=\"green\">Rules</font>\n<font color=\"blue\">Forty-nine rules are realized based on PMD, please refer the P3C-PMD documentation for more detailed information. Four rules are implemented within IDE plugins (IDEA and Eclipse) as follows:</font>  \n\n- ``[Mandatory]`` Using a deprecated class or method is prohibited.  \n   Note: For example, decode(String source, String encode) should be used instead of the deprecated method decode(String encodeStr). Once an interface has been deprecated, the interface provider has the obligation to provide a new one. At the same time, client programmers have the obligation to check out what its new implementation is.\n   \n- ``[Mandatory]`` An overridden method from an interface or abstract class must be marked with @Override annotation.\n   Counter example: For getObject() and get0bject(), the first one has a letter 'O', and the second one has a number '0'. To accurately determine whether the overriding is successful, an @Override annotation is necessary. Meanwhile, once the method signature in the abstract class is changed, the implementation class will report a compile-time error immediately.\n   \n- ``[Mandatory]`` A static field or method should be directly referred by its class name instead of its corresponding object name.\n\n- ``[Mandatory]`` The usage of hashCode and equals should follow:\n    1. Override hashCode if equals is overridden.\n    2. These two methods must be overridden for Set since they are used to ensure that no duplicate object will be inserted in Set.\n    3. These two methods must be overridden if self-defined object is used as the key of Map.\n   Note: String can be used as the key of Map since these two methods have been rewritten.\n\n"
  },
  {
    "path": "eclipse-plugin/.gitignore",
    "content": "# Gradle\nbuild\n.gradle\n\ntestdata/\n# Java gitignore #\n.class\n.log\n\n# Package Files #\n\n*.war\n*.ear\n*.gradle\n\n#hsf files\nconfiguration\n\n# maven gitignore#\ntarget/**\n\n.svn/\n\n# intelliJ.gitignore #\n.idea\n*.iml\n*.ipr\n*.iws\n*.bat\n\n# Eclipse git ignore#\n*.pydevproject\n.project\n.metadata\nbin/**\n*/bin/**\ntmp/**\ntmp/**/*\nconfiguration/**\n*.tmp\n*.bak\n*.orig\n*.swp\n*~.nib\n.classpath\n.settings/\n.loadpath\n.fileTable*\n.cache\n\n# External tool builders\n.externalToolBuilders/\n\n# Locally stored \"Eclipse launch configurations\"\n*.launch\n\n# CDT-specific\n.cproject\n\n# PDT-specific\n.buildpath\n\n#log\n*.log\n*.log.*\n\n# Windows Thumbs.db\n*.db\n\n# OSX\n.DS_Store\n\n# sass gitignore#\n.sass-cache\n.idea\n\n# tcc_coverage\ncoverage.ec\n\n\n\nconfig.client.*\n\ntemp/\n*.pid\n*.orig\n\nhsf.configuration/\n\n# code coverage report\n*.ec\n\n#hsf test\n*.instance\n**/target\n.pmd\n**/.pmd\n"
  },
  {
    "path": "eclipse-plugin/README.md",
    "content": "# Eclipse Plugin\n---\n## <font color=\"green\">Prepare</font>\n- Eclipse Juno+ \n- maven3.+\n- JDK 1.7+\n\n## <font color=\"green\">Build</font>\n```\nmvn -U clean install\n```\n## [中文使用手册](README_cn.md)\n## <font color=\"green\">Install</font>\n1. <font color=\"blue\">Help >> Install New Software\nthen enter this update site URL [https://p3c.alibaba.com/plugin/eclipse/update](https://p3c.alibaba.com/plugin/eclipse/update)</font>\n\n![Install Plugin](doc/images/install.png) \n\n2. <font color=\"blue\">Follow the wizard, restart Eclipse to take effect after install success.</font>\n\n## <font color=\"green\">Use</font>\n1. <font color=\"blue\">Switch language</font>\n\n\t![Switch language](doc/images/eclipse_switch_language.png) \n\n2. <font color=\"blue\">Code Analyze </font>\n\n  ![Analyze](doc/images/eclipse_analyze.png) \n  \n  ![Analyze](doc/images/analyze_result.png) \n    \n"
  },
  {
    "path": "eclipse-plugin/README_cn.md",
    "content": "> 首先非常感谢大家对插件的支持与意见，Eclipse的功能相对来说比较简单，希望有更多的同学加入进来一起完善。\n\n## 插件安装\n环境：JDK1.8，Eclipse4+。有同学遇到过这样的情况，安装插件重启后，发现没有对应的菜单项，从日志上也看不到相关的异常信息，最后把JDK从1.6升级到1.8解决问题。\n\nHelp -> Install New Software...\n\n![](https://gw.alicdn.com/tfscom/TB1LOyPifJNTKJjSspoXXc6mpXa.png)\n\n输入Update Site地址：https://p3c.alibaba.com/plugin/eclipse/update 回车，然后勾选Ali-CodeAnalysis，再一直点Next Next...按提示走下去就好。 然后就是提示重启了，安装完毕。\n\n![](https://gw.alicdn.com/tfscom/TB1Ud5kifBNTKJjSszcXXbO2VXa.png)\n\n注意：有同学反映插件扫描会触发很多 \"JPA Java Change Event Handler (Waiting)\" 的任务，这个是Eclipse的一个[bug](https://bugs.eclipse.org/bugs/show_bug.cgi?id=387455)，因为插件在扫描的时候会对文件进行标记，所以触发了JPA的任务。卸载JPA插件，或者尝试升级到最新版的Eclipse。附：[JPA project Change Event Handler问题解决](https://my.oschina.net/cimu/blog/278724)\n\n\n## 插件使用\n\n目前插件实现了开发手册中的53条规则，大部分基于PMD实现，其中有4条规则基于Eclipse实现，支持4条规则的QuickFix功能。\n\n\t* 所有的覆写方法，必须加@Override注解， \n \t* if/for/while/switch/do等保留字与左右括号之间都必须加空格,\n \t* long或者Long初始赋值时，必须使用大写的L，不能是小写的l）\n \t* Object的equals方法容易抛空指针异常，应使用常量或确定有值的对象来调用equals。\n \t\n目前不支持代码实时检测，需要手动触发，希望更多的人加入进来一起把咱们的插件做得越来越好，尽量提升研发的使用体验。\n\n   \n### 代码扫描\n可以通过右键菜单、Toolbar按钮两种方式手动触发代码检测。同时结果面板中可以对部分实现了QuickFix功能的规则进行快速修复。\n\n#### 触发扫描\n在当前编辑的文件中点击右键，可以在弹出的菜单中触发对该文件的检测。\n\n![](https://gw.alicdn.com/tfscom/TB1XGo8iPihSKJjy0FeXXbJtpXa.png)\n\n\n在左侧的Project目录树种点击右键，可以触发对整个工程或者选择的某个目录、文件进行检测。 \n\n![](https://gw.alicdn.com/tfscom/TB18UsJi2NZWeJjSZFpXXXjBFXa.png)\n\n   \n也可以通过Toolbar中的按钮来触发检测，目前Toolbar的按钮触发的检测范围与您IDE当时的焦点有关，如当前编辑的文件或者是Project目录树选中的项，是不是感觉与右键菜单的检测范围类似呢。 \n\n  ![](https://gw.alicdn.com/tfscom/TB1vt1oifBNTKJjSszcXXbO2VXa.png)\n\n   \n#### 扫描结果  \n简洁的结果面板，按规则等级分类，等级->规则->文件->违规项。同时还提供一个查看规则详情的界面。\n\n清除结果标记更方便，支持上面提到的4条规则QuickFix。\n\n![](https://gw.alicdn.com/tfscom/TB1_uFJi6ihSKJjy0FlXXadEXXa.png)\n\n#### 查看所有规则\n![](https://gw.alicdn.com/tfscom/TB1UNTnmYsTMeJjSszhXXcGCFXa.png)\n![](https://gw.alicdn.com/tfscom/TB1_rf7sOAKL1JjSZFoXXagCFXa.png)\n\n#### 国际化\n\n![](https://gw.alicdn.com/tfscom/TB1KsyYsiFTMKJjSZFAXXckJpXa.png) \n\n![](https://gw.alicdn.com/tfscom/TB19bzdm3oQMeJjy1XaXXcSsFXa.png)\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.feature/build.properties",
    "content": "bin.includes = feature.xml,\\\n               feature.properties,\\\n               smartfox.png\nsrc.includes = build.properties,\\\n               feature.properties,\\\n               feature.xml,\\\n               smartfox.png\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.feature/feature.properties",
    "content": "feature.label = Ali-CodeAnalysis\nfeature.provider_name = Alibaba\nfeature.update_site_name = Alibaba IDE Portal\n\ndescription.text =  Alibaba Java Coding Guidelines\ndescription.url = https://github.com/alibaba/p3c\n\ncopyright.text =\\\nCopyright 2017 Alibaba Java Coding Guidelines\n\nlicense.url = https://github.com/alibaba/p3c\nlicense.text =\\\n Copyright 1999-2017 Alibaba Group. \\n\\\n \\n\\\n Licensed under the Apache License, Version 2.0 (the \"License\"); \\n\\\n you may not use this file except in compliance with the License. \\n\\\n You may obtain a copy of the License at \\n\\\n \\n\\\n      http://www.apache.org/licenses/LICENSE-2.0 \\n\\\n \\n\\\n Unless required by applicable law or agreed to in writing, software \\n\\\n distributed under the License is distributed on an \"AS IS\" BASIS, \\n\\\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \\n\\\n See the License for the specific language governing permissions and \\n\\\n limitations under the License. \\n\\\n\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.feature/feature.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feature\n        id=\"com.alibaba.smartfox.eclipse.feature\"\n        label=\"%feature.label\"\n        version=\"2.0.1.qualifier\"\n        provider-name=\"%feature.provider_name\"\n        plugin=\"com.alibaba.smartfox.eclipse.plugin\"\n        image=\"smartfox.png\">\n\n    <description url=\"%description.url\">\n        Alibaba Java Coding Guidelines\n    </description>\n\n    <copyright>\n        %copyright.text\n    </copyright>\n\n    <license url=\"%license.url\">\n        %license.text\n    </license>\n\n    <url>\n        <update label=\"%feature.update_site_name\" url=\"https://p3c.alibaba.com/plugin/eclipse/update\"/>\n    </url>\n\n    <requires>\n        <import plugin=\"org.eclipse.ui\"/>\n        <import plugin=\"org.eclipse.core.runtime\"/>\n        <import plugin=\"org.eclipse.jdt.core\"/>\n        <import plugin=\"org.eclipse.ui.ide\"/>\n        <import plugin=\"org.eclipse.ui.views\"/>\n        <import plugin=\"org.eclipse.core.resources\"/>\n        <import plugin=\"org.eclipse.jface.text\"/>\n        <import plugin=\"org.eclipse.ui.workbench.texteditor\"/>\n        <import plugin=\"org.eclipse.ltk.core.refactoring\"/>\n        <import plugin=\"org.eclipse.jdt.ui\"/>\n        <import plugin=\"org.eclipse.core.filebuffers\"/>\n    </requires>\n\n    <plugin\n            id=\"com.alibaba.smartfox.eclipse.plugin\"\n            download-size=\"0\"\n            install-size=\"0\"\n            version=\"0.0.0\"/>\n\n</feature>\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.feature/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>com.alibaba.smartfox.eclipse</groupId>\n    <artifactId>smartfox-eclipse</artifactId>\n    <version>2.0.1-SNAPSHOT</version>\n  </parent>\n  <artifactId>com.alibaba.smartfox.eclipse.feature</artifactId>\n  <packaging>eclipse-feature</packaging>\n  <inceptionYear>2017</inceptionYear>\n</project>\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: com.alibaba.smartfox.eclipse.plugin\nBundle-SymbolicName: com.alibaba.smartfox.eclipse.plugin;singleton:=true\nBundle-Version: 2.0.1.qualifier\nBundle-Activator: com.alibaba.smartfox.eclipse.SmartfoxActivator\nBundle-Vendor: Alibaba\nRequire-Bundle: org.eclipse.ui,\n org.eclipse.core.runtime,\n org.eclipse.jdt.core,\n org.eclipse.ui.ide,\n org.eclipse.ui.views,\n org.eclipse.core.resources,\n org.eclipse.jface.text,\n org.eclipse.ui.workbench.texteditor,\n org.eclipse.ltk.core.refactoring,\n org.eclipse.jdt.ui,\n org.eclipse.core.filebuffers,\n org.eclipse.equinox.p2.core,\n org.eclipse.equinox.p2.engine,\n org.eclipse.equinox.p2.operations,\n org.eclipse.equinox.p2.metadata.repository,\n org.eclipse.equinox.p2.ui,\n org.eclipse.equinox.p2.metadata\nBundle-RequiredExecutionEnvironment: JavaSE-1.8\nBundle-ActivationPolicy: lazy\nBundle-ClassPath: target/lib/antlr-runtime.jar,\n target/lib/antlr4-runtime.jar,\n target/lib/asm.jar,\n target/lib/commons-io.jar,\n target/lib/commons-lang3.jar,\n target/lib/gson.jar,\n target/lib/javacc.jar,\n target/lib/jaxen.jar,\n target/lib/jcommander.jar,\n target/lib/log4j.jar,\n target/lib/pmd-core.jar,\n target/lib/pmd-java.jar,\n target/lib/pmd-javascript.jar,\n target/lib/pmd-vm.jar,\n target/lib/rhino.jar,\n target/lib/saxon-dom.jar,\n target/lib/saxon.jar,\n target/lib/p3c-pmd.jar,\n target/lib/kotlin-stdlib.jar,\n  target/lib/statistics-client.jar,\n    target/lib/guava.jar,\n target/classes/,\n .\nBundle-Localization: plugin\nExport-Package: com.alibaba.smartfox.eclipse,\n com.alibaba.smartfox.eclipse.handler,\n com.alibaba.smartfox.eclipse.job,\n com.alibaba.smartfox.eclipse.marker,\n com.alibaba.smartfox.eclipse.pmd,\n com.alibaba.smartfox.eclipse.pmd.rule,\n com.alibaba.smartfox.eclipse.ui,\n com.alibaba.smartfox.eclipse.ui.pmd,\n com.alibaba.smartfox.eclipse.util\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               plugin.xml,\\\n               icons/,\\\n               target/lib/\nsrc.includes = icons/,\\\n               META-INF/,\\\n               plugin.xml,\\\n               messages.properties,\\\n               target/lib/,\\\n               src/main/kotlin,\\\n               pom.xml\nsource.. = src/main/java/,src/main/resources\noutput.. = target/classes/\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?eclipse version=\"3.4\"?>\n<plugin>\n    <extension\n          id=\"SmartFoxViews\"\n          name=\"SmartFoxViews\"\n          point=\"org.eclipse.ui.views\">\n        <category\n                name=\"SmartFoxViews\"\n                id=\"com.alibaba.smartfox.eclipse.ui\">\n        </category>\n        <view\n                name=\"P3C Results\"\n                allowMultiple=\"false\"\n                icon=\"icons/view/smartfox_logo.png\"\n                category=\"com.alibaba.smartfox.eclipse.ui\"\n                class=\"com.alibaba.smartfox.eclipse.ui.InspectionResultView\"\n                id=\"com.alibaba.smartfox.eclipse.ui.InspectionResultView\">\n        </view>\n        <view\n                name=\"Rule Detail\"\n                allowMultiple=\"false\"\n                icon=\"icons/view/smartfox_logo.png\"\n                category=\"com.alibaba.smartfox.eclipse.ui\"\n                class=\"com.alibaba.smartfox.eclipse.ui.RuleDetailView\"\n                id=\"com.alibaba.smartfox.eclipse.ui.RuleDetailView\">\n        </view>\n        <stickyView\n                location=\"LEFT\"\n                id=\"com.alibaba.smartfox.eclipse.ui.RuleDetailView\">\n        </stickyView>\n    </extension>\n\n    <extension point=\"org.eclipse.core.expressions.definitions\">\n        <definition id=\"when.alibaba.analysis.is.active\">\n            <or>\n                <with variable=\"activePartId\">\n                    <equals\n                            value=\"org.eclipse.jdt.ui.PackageExplorer\">\n                    </equals>\n                </with>\n                <with variable=\"activePartId\">\n                    <equals\n                            value=\"org.eclipse.ui.navigator.ProjectExplorer\">\n                    </equals>\n                </with>\n                <with variable=\"activeSite\">\n                    <adapt\n                            type=\"org.eclipse.ui.IEditorSite\">\n                    </adapt>\n\n                </with>\n            </or>\n\n        </definition>\n    </extension>\n    <extension\n            point=\"org.eclipse.ui.commands\">\n        <category\n                description=\"Alibaba Code Analysis\"\n                id=\"alibaba.ui.commands\"\n                name=\"Alibaba Command\">\n        </category>\n        <command\n                categoryId=\"alibaba.ui.commands\"\n                description=\"Alibaba Code Analysis\"\n                id=\"com.alibaba.smartfox.eclipse.command.analysis\"\n                name=\"Alibaba Code Analysis\"/>\n        <command\n                categoryId=\"alibaba.ui.commands\"\n                description=\"Alibaba Code Analysis\"\n                id=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler\"\n                name=\"Switch Language\"/>\n    </extension>\n    <extension\n            point=\"org.eclipse.ui.bindings\">\n        <key\n                commandId=\"com.alibaba.smartfox.eclipse.command.analysis\"\n                contextId=\"org.eclipse.ui.contexts.window\"\n                schemeId=\"org.eclipse.ui.defaultAcceleratorConfiguration\"\n                sequence=\"Ctrl+Shift+Alt+J\">\n        </key>\n    </extension>\n    <extension\n            point=\"org.eclipse.ui.handlers\">\n        <handler\n                class=\"com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler\"\n                commandId=\"com.alibaba.smartfox.eclipse.command.analysis\">\n            <enabledWhen>\n                <reference\n                        definitionId=\"when.alibaba.analysis.is.active\">\n                </reference>\n            </enabledWhen>\n        </handler>\n        <handler\n                class=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler\"\n                commandId=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler\">\n        </handler>\n    </extension>\n    <extension point=\"org.eclipse.ui.menus\">\n        <menuContribution allPopups=\"false\"\n                          locationURI=\"popup:org.eclipse.ui.popup.any\">\n            <command\n                    commandId=\"com.alibaba.smartfox.eclipse.command.analysis\"\n                    icon=\"icons/ali-ide-run.png\"\n                    label=\"Alibaba Code Guidelines\"\n                    style=\"push\">\n                <visibleWhen\n                        checkEnabled=\"false\">\n                    <reference definitionId=\"when.alibaba.analysis.is.active\"/>\n                </visibleWhen>\n            </command>\n        </menuContribution>\n        <menuContribution\n                allPopups=\"false\"\n                locationURI=\"toolbar:org.eclipse.ui.main.toolbar?after=additions\">\n            <toolbar\n                    id=\"com.alibaba.smartfox.eclipse.plugin.toolbar3\">\n                <command\n                        commandId=\"com.alibaba.smartfox.eclipse.command.analysis\"\n                        icon=\"icons/ali-ide-run.png\"\n                        label=\"Alibaba Code Guidelines\"\n                        style=\"push\"\n                        tooltip=\"Alibaba Code Guidelines\">\n                </command>\n                <command\n                        commandId=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler\"\n                        icon=\"icons/language.png\"\n                        label=\"Switch Language\"\n                        style=\"push\"\n                        tooltip=\"Switch Language\">\n                </command>\n            </toolbar>\n        </menuContribution>\n    </extension>\n    <extension\n            id=\"p3cMarker\"\n            name=\"P3C Violations\"\n            point=\"org.eclipse.core.resources.markers\">\n        <persistent value=\"false\"/>\n        <super type=\"org.eclipse.core.resources.problemmarker\"/>\n    </extension>\n    <extension point=\"org.eclipse.ui.ide.markerResolution\">\n        <markerResolutionGenerator\n                markerType=\"com.alibaba.smartfox.eclipse.plugin.p3cMarker\"\n                class=\"com.alibaba.smartfox.eclipse.QuickFixGenerator\"/>\n    </extension>\n    <extension point=\"org.eclipse.ui.preferencePages\">\n        <page name=\"Alibaba Code Analysis\"\n              class=\"com.alibaba.smartfox.eclipse.ui.AllRulesPreferencePage\"\n              id=\"com.alibaba.smartfox.eclipse.ui.AllRulesPreferencePage\"/>\n    </extension>\n</plugin>\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>com.alibaba.smartfox.eclipse</groupId>\n    <artifactId>smartfox-eclipse</artifactId>\n    <version>2.0.1-SNAPSHOT</version>\n  </parent>\n  <artifactId>com.alibaba.smartfox.eclipse.plugin</artifactId>\n  <packaging>eclipse-plugin</packaging>\n  <inceptionYear>2017</inceptionYear>\n  <properties>\n    <kotlin.compiler.incremental>false</kotlin.compiler.incremental>\n  </properties>\n  <dependencies>\n    <dependency>\n      <groupId>log4j</groupId>\n      <artifactId>log4j</artifactId>\n      <version>1.2.17</version>\n    </dependency>\n    <dependency>\n      <groupId>com.alibaba.p3c</groupId>\n      <artifactId>p3c-pmd</artifactId>\n      <version>2.0.1</version>\n    </dependency>\n    <dependency>\n      <groupId>org.jetbrains.kotlin</groupId>\n      <artifactId>kotlin-stdlib-jdk8</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>com.google.guava</groupId>\n      <artifactId>guava</artifactId>\n      <version>20.0</version>\n    </dependency>\n  </dependencies>\n  <build>\n    <sourceDirectory>src/main/kotlin</sourceDirectory>\n    <plugins>\n      <plugin>\n        <groupId>org.jetbrains.kotlin</groupId>\n        <artifactId>kotlin-maven-plugin</artifactId>\n        <version>${kotlin.version}</version>\n\n        <executions>\n          <execution>\n            <id>compile</id>\n            <phase>compile</phase>\n            <goals>\n              <goal>compile</goal>\n            </goals>\n          </execution>\n\n          <execution>\n            <id>test-compile</id>\n            <phase>test-compile</phase>\n            <goals>\n              <goal>test-compile</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-dependency-plugin</artifactId>\n        <version>3.1.1</version>\n        <configuration>\n          <stripVersion>true</stripVersion>\n          <prependGroupId>false</prependGroupId>\n          <outputDirectory>${project.build.directory}/lib</outputDirectory>\n          <!-- exclude the apex (transitive) dependencies - we use the shaded\n              version instead -->\n          <excludeGroupIds>p2.eclipse-plugin,apex</excludeGroupIds>\n          <excludeArtifactIds>com.alibaba.smartfox.eclipse.plugin\n          </excludeArtifactIds>\n          <useRepositoryLayout>false</useRepositoryLayout>\n        </configuration>\n        <executions>\n          <execution>\n            <id>get-dependencies</id>\n            <phase>process-sources</phase>\n            <goals>\n              <goal>copy-dependencies</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n    <pluginManagement>\n      <plugins>\n        <!--This plugin's configuration is used to store Eclipse m2e settings\n            only. It has no influence on the Maven build itself. -->\n        <plugin>\n          <groupId>org.eclipse.m2e</groupId>\n          <artifactId>lifecycle-mapping</artifactId>\n          <version>1.0.0</version>\n          <configuration>\n            <lifecycleMappingMetadata>\n              <pluginExecutions>\n                <pluginExecution>\n                  <pluginExecutionFilter>\n                    <groupId>\n                      org.apache.maven.plugins\n                    </groupId>\n                    <artifactId>\n                      maven-dependency-plugin\n                    </artifactId>\n                    <versionRange>[0,)</versionRange>\n                    <goals>\n                      <goal>copy-dependencies</goal>\n                    </goals>\n                  </pluginExecutionFilter>\n                  <action>\n                    <ignore></ignore>\n                  </action>\n                </pluginExecution>\n              </pluginExecutions>\n            </lifecycleMappingMetadata>\n          </configuration>\n        </plugin>\n      </plugins>\n    </pluginManagement>\n  </build>\n</project>\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/QuickFix.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse\n\nimport com.alibaba.p3c.pmd.lang.java.rule.constant.UpperEllRule\nimport com.alibaba.p3c.pmd.lang.java.rule.oop.EqualsAvoidNullRule\nimport com.alibaba.smartfox.eclipse.ui.InspectionResults\nimport com.alibaba.smartfox.eclipse.util.getRule\nimport com.google.common.io.Files\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.resources.IMarker\nimport org.eclipse.core.runtime.NullProgressMonitor\nimport org.eclipse.ltk.core.refactoring.TextFileChange\nimport org.eclipse.text.edits.ReplaceEdit\nimport org.eclipse.ui.IMarkerResolution\nimport org.eclipse.ui.IMarkerResolutionGenerator\nimport java.nio.charset.Charset\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/14\n */\nclass QuickFixGenerator : IMarkerResolutionGenerator {\n    override fun getResolutions(marker: IMarker): Array<IMarkerResolution> {\n        if (!marker.exists()) {\n            return emptyArray()\n        }\n        val rule = marker.getRule()\n        val quickFix = quickFixes[rule.name] ?: return emptyArray()\n        return arrayOf(quickFix)\n    }\n\n    companion object {\n        val quickFixes = mapOf(UpperEllRule::class.java.simpleName to UpperEllQuickFix,\n                EqualsAvoidNullRule::class.java.simpleName to EqualsAvoidNullQuickFix)\n    }\n}\n\ninterface RunWithoutViewRefresh : IMarkerResolution {\n    fun run(marker: IMarker, refresh: Boolean)\n\n    override fun run(marker: IMarker) {\n        run(marker, true)\n    }\n}\n\nabstract class BaseQuickFix : RunWithoutViewRefresh {\n    override fun run(marker: IMarker, refresh: Boolean) {\n        if (!marker.exists()) {\n            return\n        }\n        val file = marker.resource as IFile\n        doRun(marker, file)\n        marker.delete()\n        if (refresh) {\n            InspectionResults.removeMarker(marker)\n        }\n    }\n\n    abstract fun doRun(marker: IMarker, file: IFile)\n}\n\nobject UpperEllQuickFix : BaseQuickFix() {\n    override fun doRun(marker: IMarker, file: IFile) {\n        val offset = marker.getAttribute(IMarker.CHAR_START, 0)\n        val end = marker.getAttribute(IMarker.CHAR_END, 0)\n        val content = Files.toString(file.rawLocation.toFile(), Charset.forName(file.charset))\n        val replaceString = content.substring(offset, end + 1).replace(\"l\", \"L\")\n        val edit = ReplaceEdit(offset, replaceString.length, replaceString)\n        val change = TextFileChange(\"\", file)\n        change.edit = edit\n        change.perform(NullProgressMonitor())\n    }\n\n    override fun getLabel(): String {\n        return \"Replace 'l' to 'L'.\"\n    }\n\n}\n\nobject EqualsAvoidNullQuickFix : BaseQuickFix() {\n    val equalsName = \".equals(\"\n\n    override fun doRun(marker: IMarker, file: IFile) {\n        val offset = marker.getAttribute(IMarker.CHAR_START, 0)\n        val end = marker.getAttribute(IMarker.CHAR_END, 0)\n        val content = Files.toString(file.rawLocation.toFile(), Charset.forName(file.charset))\n        val string = content.substring(offset, end)\n        val list = string.split(equalsName).filterNotNull()\n        if (list.size != 2) {\n            return\n        }\n        val replace = \"${list[1].substringBeforeLast(')')}$equalsName${list[0]})\"\n        val edit = ReplaceEdit(offset, string.length, replace)\n        val change = TextFileChange(\"\", file)\n        change.edit = edit\n        change.perform(NullProgressMonitor())\n    }\n\n    override fun getLabel(): String {\n        return \"Flip equals.\"\n    }\n\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/SmartfoxActivator.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse\n\nimport com.alibaba.p3c.pmd.I18nResources\nimport net.sourceforge.pmd.Rule\nimport net.sourceforge.pmd.RuleSetFactory\nimport net.sourceforge.pmd.RuleSets\nimport org.apache.log4j.Logger\nimport org.eclipse.core.runtime.IStatus\nimport org.eclipse.core.runtime.Status\nimport org.eclipse.jface.dialogs.MessageDialog\nimport org.eclipse.jface.resource.ImageDescriptor\nimport org.eclipse.swt.graphics.Image\nimport org.eclipse.swt.widgets.Display\nimport org.eclipse.ui.plugin.AbstractUIPlugin\nimport org.osgi.framework.BundleContext\nimport java.util.Locale\n\n/**\n * @author caikang\n * @date 2017/06/14\n */\nclass SmartfoxActivator : AbstractUIPlugin() {\n\n    init {\n        aDefault = this\n    }\n\n    private val logger = Logger.getLogger(javaClass)!!\n    lateinit var ruleSets: RuleSets\n    private val localeKey = \"p3c.locale\"\n\n    lateinit var ruleMap: Map<String, Rule>\n\n    @Throws(Exception::class) override fun start(context: BundleContext) {\n        super.start(context)\n        I18nResources.changeLanguage(locale)\n        ruleSets = createRuleSets()\n        ruleMap = ruleSets.allRules.associateBy {\n            it.name\n        }\n    }\n\n    @Throws(Exception::class) override fun stop(context: BundleContext?) {\n        aDefault = null\n        super.stop(context)\n    }\n\n\n    fun getImage(key: String, iconPath: String = key): Image {\n        val registry = imageRegistry\n        var image: Image? = registry.get(key)\n        if (image == null) {\n            val descriptor = getImageDescriptor(iconPath)\n            registry.put(key, descriptor)\n            image = registry.get(key)\n        }\n\n        return image!!\n    }\n\n    val locale: String\n        get() {\n            val language = preferenceStore.getString(localeKey)\n            if (language.isNullOrBlank()) {\n                val lang = Locale.getDefault().language\n                return if (lang != Locale.ENGLISH.language && lang != Locale.CHINESE.language) {\n                    Locale.ENGLISH.language\n                } else Locale.getDefault().language\n            }\n\n            return language\n        }\n\n    fun toggleLocale() {\n        val lang = if (Locale.ENGLISH.language == locale) Locale.CHINESE.language else Locale.ENGLISH.language\n        preferenceStore.setValue(localeKey, lang)\n    }\n\n    fun getRule(rule: String): Rule {\n        return ruleMap[rule]!!\n    }\n\n    fun showError(message: String, t: Throwable) {\n        logError(message, t)\n        Display.getDefault().syncExec {\n            MessageDialog.openError(Display.getCurrent().activeShell, \"错误\", message + \"\\n\" + t.toString())\n        }\n    }\n\n    fun logError(message: String, t: Throwable) {\n        log.log(Status(IStatus.ERROR, bundle.symbolicName, 0, message + t.message, t))\n        logger.error(message, t)\n    }\n\n    fun logError(status: IStatus) {\n        log.log(status)\n        logger.error(status.message, status.exception)\n    }\n\n    fun logInformation(message: String) {\n        log.log(Status(IStatus.INFO, bundle.symbolicName, 0, message, null))\n    }\n\n    fun logWarn(message: String) {\n        log.log(Status(IStatus.WARNING, bundle.symbolicName, 0, message, null))\n    }\n\n    companion object {\n        // The plug-in ID\n        val PLUGIN_ID = \"com.alibaba.smartfox.eclipse.plugin\"\n\n        var aDefault: SmartfoxActivator? = null\n            private set\n\n        val instance: SmartfoxActivator get() = aDefault!!\n\n        fun getImageDescriptor(path: String): ImageDescriptor {\n            return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path)\n        }\n\n        fun createRuleSets(): RuleSets {\n            val ruleSetFactory = RuleSetFactory()\n            return ruleSetFactory.createRuleSets(\"java-ali-pmd,vm-ali-other\")\n        }\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/handler/CodeAnalysisHandler.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.handler\n\nimport com.alibaba.smartfox.eclipse.job.CodeAnalysis.processResources\nimport com.alibaba.smartfox.eclipse.message.P3cBundle\nimport com.google.common.collect.Sets\nimport org.apache.log4j.Logger\nimport org.eclipse.core.commands.AbstractHandler\nimport org.eclipse.core.commands.ExecutionEvent\nimport org.eclipse.core.commands.ExecutionException\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.resources.IResource\nimport org.eclipse.core.resources.IResourceVisitor\nimport org.eclipse.core.runtime.IAdaptable\nimport org.eclipse.jface.viewers.IStructuredSelection\nimport org.eclipse.ui.IFileEditorInput\nimport org.eclipse.ui.IWorkingSet\nimport org.eclipse.ui.commands.IElementUpdater\nimport org.eclipse.ui.handlers.HandlerUtil\nimport org.eclipse.ui.menus.UIElement\nimport org.eclipse.ui.part.EditorPart\nimport org.eclipse.ui.part.ViewPart\n\n/**\n * @author caikang\n * @date 2016/12/27\n */\nopen class CodeAnalysisHandler : AbstractHandler(), IElementUpdater {\n    override fun updateElement(element: UIElement, parameters: MutableMap<Any?, Any?>?) {\n        val text = P3cBundle.getMessage(\"com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler\")\n        element.setText(text)\n        element.setTooltip(text)\n    }\n\n    @Throws(ExecutionException::class)\n    override fun execute(executionEvent: ExecutionEvent): Any? {\n        val selection = HandlerUtil.getCurrentSelectionChecked(executionEvent)\n        val part = HandlerUtil.getActivePart(executionEvent)\n        if (part is ViewPart) {\n            if (selection is IStructuredSelection) {\n                processForMutiFiles(selection)\n            }\n        } else if (part is EditorPart) {\n            val editorInput = HandlerUtil.getActiveEditorInput(executionEvent)\n            if (editorInput is IFileEditorInput) {\n                processResources(setOf(editorInput.file))\n            }\n        }\n        return null\n    }\n\n    private fun processForMutiFiles(selection: IStructuredSelection) {\n        val resources = getSelectionResources(selection)\n        processResources(resources)\n    }\n\n    private fun getSelectionResources(selection: IStructuredSelection): MutableSet<IResource> {\n        val resources = mutableSetOf<IResource>()\n        selection.toList().forEach {\n            when (it) {\n                is IWorkingSet -> it.elements.mapTo(resources) { it.getAdapter(IResource::class.java) as IResource }\n                is IAdaptable -> {\n                    val file = it.getAdapter(IResource::class.java) as? IResource ?: return@forEach\n                    resources.add(file)\n                }\n                else -> log.warn(\"The selected object is not adaptable : ${it.toString()}\")\n            }\n        }\n        return resources\n    }\n\n\n    companion object {\n        private val log = Logger.getLogger(CodeAnalysisHandler::class.java)\n    }\n}\n\nclass FileCollectVisitor : IResourceVisitor {\n    val fileSet = Sets.newLinkedHashSet<IFile>()!!\n\n    override fun visit(resource: IResource?): Boolean {\n        if (resource == null) {\n            return false\n        }\n        val file = resource.getAdapter(IFile::class.java) as? IFile ?: return true\n        if (file.exists() && (file.fileExtension == \"java\" || file.fileExtension == \"vm\")) {\n            fileSet.add(file)\n        }\n        return false\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/handler/SwitchLanguageHandler.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.handler\n\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport com.alibaba.smartfox.eclipse.message.P3cBundle\nimport org.eclipse.core.commands.AbstractHandler\nimport org.eclipse.core.commands.ExecutionEvent\nimport org.eclipse.jface.dialogs.MessageDialog\nimport org.eclipse.ui.PlatformUI\nimport org.eclipse.ui.commands.IElementUpdater\nimport org.eclipse.ui.menus.UIElement\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/21\n */\nclass SwitchLanguageHandler : AbstractHandler(), IElementUpdater {\n    val handlerKey = \"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler\"\n    val textKey = \"$handlerKey.text.cur_\"\n\n    override fun execute(executionEvent: ExecutionEvent): Any? {\n        SmartfoxActivator.instance.toggleLocale()\n        if (!MessageDialog.openConfirm(null, \"Tips\",\n                P3cBundle.getMessage(\"$handlerKey.success.${SmartfoxActivator.instance.locale}\"))) {\n            return null\n        }\n        PlatformUI.getWorkbench().restart()\n        return null\n    }\n\n    override fun updateElement(element: UIElement, parameters: MutableMap<Any?, Any?>?) {\n        val text = P3cBundle.getMessage(\"$textKey${SmartfoxActivator.instance.locale}\")\n        element.setText(text)\n        element.setTooltip(text)\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/job/CodeAnalysis.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.job\n\nimport com.alibaba.p3c.pmd.lang.java.util.GeneratedCodeUtils\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler\nimport com.alibaba.smartfox.eclipse.handler.FileCollectVisitor\nimport com.alibaba.smartfox.eclipse.ui.InspectionResultView\nimport com.alibaba.smartfox.eclipse.ui.InspectionResults\nimport com.alibaba.smartfox.eclipse.ui.MarkerViolation\nimport com.alibaba.smartfox.eclipse.util.MarkerUtil\nimport com.google.common.io.Files\nimport net.sourceforge.pmd.PMDConfiguration\nimport net.sourceforge.pmd.PMDException\nimport net.sourceforge.pmd.Report\nimport net.sourceforge.pmd.RuleContext\nimport net.sourceforge.pmd.RuleViolation\nimport net.sourceforge.pmd.SourceCodeProcessor\nimport org.apache.log4j.Logger\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.resources.IResource\nimport org.eclipse.core.runtime.IProgressMonitor\nimport org.eclipse.core.runtime.IStatus\nimport org.eclipse.core.runtime.Status\nimport org.eclipse.core.runtime.SubMonitor\nimport org.eclipse.core.runtime.jobs.Job\nimport java.io.IOException\nimport java.io.StringReader\nimport java.nio.charset.Charset\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/14\n */\nobject CodeAnalysis {\n    private val log = Logger.getLogger(CodeAnalysisHandler::class.java)\n\n    fun processResources(resources: Set<IResource>) {\n        InspectionResultView.activeViews()\n        val job = object : Job(\"P3C Code Analysis\") {\n            override fun run(monitor: IProgressMonitor): IStatus {\n                val fileVisitor = FileCollectVisitor()\n                monitor.setTaskName(\"Collect files\")\n                resources.forEach {\n                    if (monitor.isCanceled) {\n                        return@run Status.CANCEL_STATUS\n                    }\n                    if (it.isAccessible) {\n                        it.accept(fileVisitor)\n                    }\n                }\n                if (monitor.isCanceled) {\n                    return Status.CANCEL_STATUS\n                }\n                val subMonitor = SubMonitor.convert(monitor, \"Analysis files\", fileVisitor.fileSet.size)\n                monitor.setTaskName(\"Analysis files\")\n                fileVisitor.fileSet.forEach { iFile ->\n                    if (monitor.isCanceled) {\n                        return@run Status.CANCEL_STATUS\n                    }\n                    MarkerUtil.removeAllMarkers(iFile)\n                    monitor.subTask(iFile.fullPath.toPortableString())\n                    val markers = processFileToMakers(iFile, monitor)\n                    subMonitor.newChild(1)\n                    InspectionResults.updateFileViolations(iFile, markers)\n                }\n                return Status.OK_STATUS\n            }\n        }\n        job.apply {\n            isUser = true\n            isSystem = false\n            priority = Job.INTERACTIVE\n            rule = P3cMutex\n            schedule()\n        }\n    }\n\n    fun processFileToMakers(file: IFile, monitor: IProgressMonitor): List<MarkerViolation> {\n        file.refreshLocal(IResource.DEPTH_ZERO, monitor)\n        val ruleViolations = processFile(file)\n\n        MarkerUtil.removeAllMarkers(file)\n        return ruleViolations.map {\n            MarkerViolation(MarkerUtil.addMarker(file, it), it)\n        }\n    }\n\n    private fun processFile(file: IFile): List<RuleViolation> {\n        val configuration = PMDConfiguration()\n        configuration.setSourceEncoding(file.charset ?: Charsets.UTF_8.name())\n        configuration.inputPaths = file.fullPath.toPortableString()\n        val ctx = RuleContext()\n        ctx.setAttribute(\"eclipseFile\", file)\n        val niceFileName = configuration.inputPaths\n        val report = Report.createReport(ctx, niceFileName)\n        SmartfoxActivator.instance.ruleSets.start(ctx)\n        val processor = SourceCodeProcessor(configuration)\n        try {\n            ctx.languageVersion = null\n            val content = Files.toString(file.rawLocation.toFile(), Charset.forName(file.charset))\n            if (!GeneratedCodeUtils.isGenerated(content)) {\n                processor.processSourceCode(StringReader(content), SmartfoxActivator.instance.ruleSets, ctx)\n            }\n        } catch (pmde: PMDException) {\n            log.debug(\"Error while processing file: \" + niceFileName, pmde.cause)\n            report.addError(Report.ProcessingError(pmde, niceFileName))\n        } catch (ioe: IOException) {\n            log.error(\"Unable to read source file: \" + niceFileName, ioe)\n        } catch (re: RuntimeException) {\n            log.error(\"RuntimeException while processing file: \" + niceFileName, re)\n        } finally {\n            SmartfoxActivator.instance.ruleSets.end(ctx)\n        }\n        return report.toList()\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/job/P3cMutex.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.job\n\nimport org.eclipse.core.runtime.jobs.ISchedulingRule\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/14\n */\nobject P3cMutex : ISchedulingRule {\n    override fun contains(rule: ISchedulingRule?): Boolean {\n        return isConflicting(rule)\n    }\n\n    override fun isConflicting(rule: ISchedulingRule?): Boolean {\n        return rule == this\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/message/P3cBundle.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.message\n\n\nimport com.alibaba.p3c.pmd.I18nResources\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport java.util.Locale\nimport java.util.ResourceBundle\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/20\n */\nobject P3cBundle {\n    private val resourceBundle = ResourceBundle.getBundle(\"messages.P3cBundle\",\n            Locale(SmartfoxActivator.instance.locale), I18nResources.XmlControl())\n\n    fun getMessage(key: String): String {\n        return resourceBundle.getString(key)\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/RulePriority.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.pmd\n\nenum class RulePriority(val priority: Int, val title: String) {\n\n    Blocker(1, \"Blocker\"), Critical(2, \"Critical\"), Major(3, \"Major\");\n\n    override fun toString(): String {\n        return title\n    }\n\n    companion object {\n        fun valueOf(priority: Int): RulePriority {\n            try {\n                return RulePriority.values()[priority - 1]\n            } catch (e: ArrayIndexOutOfBoundsException) {\n                return Major\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AbstractEclipseRule.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.pmd.rule\n\nimport com.alibaba.smartfox.eclipse.message.P3cBundle\nimport net.sourceforge.pmd.Rule\nimport net.sourceforge.pmd.RuleContext\nimport net.sourceforge.pmd.RuleViolation\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit\nimport net.sourceforge.pmd.lang.java.rule.AbstractJavaRule\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.runtime.NullProgressMonitor\nimport org.eclipse.jdt.core.ICompilationUnit\nimport org.eclipse.jdt.core.IProblemRequestor\nimport org.eclipse.jdt.core.JavaCore\nimport org.eclipse.jdt.core.JavaModelException\nimport org.eclipse.jdt.core.WorkingCopyOwner\nimport org.eclipse.jdt.core.compiler.IProblem\nimport org.eclipse.jdt.core.dom.ASTNode\nimport org.eclipse.jdt.core.dom.ASTVisitor\nimport org.eclipse.jdt.core.dom.CompilationUnit\nimport java.util.MissingResourceException\n\n/**\n * @author caikang\n * @date 2016/12/26\n */\nabstract class AbstractEclipseRule : AbstractJavaRule() {\n\n    open fun getErrorMessage(): String {\n        return message\n    }\n\n    override fun visit(node: ASTCompilationUnit, data: Any): Any? {\n        val result = super.visit(node, data)\n        val ruleContext = data as RuleContext\n        val file = ruleContext.getAttribute(\"eclipseFile\") as? IFile ?: return result\n        val compilationUnit = JavaCore.createCompilationUnitFrom(file) ?: return data\n        try {\n            val requestor = object : IProblemRequestor {\n                override fun acceptProblem(problem: IProblem) {}\n\n                override fun beginReporting() {}\n\n                override fun endReporting() {}\n\n                override fun isActive(): Boolean {\n                    return true\n                }\n            }\n            val workingCopy = compilationUnit.getWorkingCopy(null)\n            val ast = workingCopy.reconcile(JLS8, ICompilationUnit.FORCE_PROBLEM_DETECTION\n                    or ICompilationUnit.ENABLE_BINDINGS_RECOVERY or ICompilationUnit.ENABLE_STATEMENTS_RECOVERY,\n                    object : WorkingCopyOwner() {\n                        override fun getProblemRequestor(workingCopy: ICompilationUnit?): IProblemRequestor {\n                            return requestor\n                        }\n                    }, NullProgressMonitor()) ?: return data\n            ast.accept(getVisitor(ast, ruleContext))\n\n        } catch (e: JavaModelException) {\n            throw RuntimeException(e)\n        }\n\n        return data\n    }\n\n    override fun setDescription(description: String?) {\n        try {\n            super.setDescription(P3cBundle.getMessage(description ?: \"\"))\n        } catch (e: MissingResourceException) {\n            super.setMessage(description)\n        }\n\n    }\n\n    override fun setMessage(message: String) {\n        try {\n            super.setMessage(P3cBundle.getMessage(message))\n        } catch (e: MissingResourceException) {\n            super.setMessage(message)\n        }\n\n    }\n\n\n    protected abstract fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor\n\n    internal fun addRuleViolation(ruleContext: RuleContext, ast: CompilationUnit, nodeInfo: NodeInfo) {\n        val rule = this\n        val ruleViolation = object : RuleViolation {\n            override fun getRule(): Rule {\n                return rule\n            }\n\n            override fun getDescription(): String {\n                return getErrorMessage().trim { it <= ' ' }\n            }\n\n            override fun isSuppressed(): Boolean {\n                return false\n            }\n\n            override fun getFilename(): String {\n                return ruleContext.sourceCodeFilename\n            }\n\n            override fun getBeginLine(): Int {\n                return ast.getLineNumber(nodeInfo.startPosition)\n            }\n\n            override fun getBeginColumn(): Int {\n                return ast.getColumnNumber(nodeInfo.startPosition)\n            }\n\n            override fun getEndLine(): Int {\n                return ast.getLineNumber(nodeInfo.endPosition)\n            }\n\n            override fun getEndColumn(): Int {\n                return ast.getColumnNumber(nodeInfo.endPosition)\n            }\n\n            override fun getPackageName(): String? {\n                return nodeInfo.packageName\n            }\n\n            override fun getClassName(): String? {\n                return nodeInfo.className\n            }\n\n            override fun getMethodName(): String? {\n                return nodeInfo.methodName\n            }\n\n            override fun getVariableName(): String? {\n                return nodeInfo.variableName\n            }\n\n            override fun toString(): String {\n                return rule.toString()\n            }\n\n\n        }\n\n        ruleContext.report.addRuleViolation(ruleViolation)\n    }\n\n    protected fun violation(rc: RuleContext, node: ASTNode, ast: CompilationUnit) {\n        val nodeInfo = NodeInfo()\n        nodeInfo.className = ast.javaElement.elementName\n        nodeInfo.packageName = ast.`package`.name.fullyQualifiedName\n        nodeInfo.startPosition = node.startPosition\n        nodeInfo.endPosition = node.startPosition + node.length\n\n        addRuleViolation(rc, ast, nodeInfo)\n    }\n\n    inner class NodeInfo {\n        internal var packageName: String? = null\n        internal var className: String? = null\n        internal var methodName: String? = null\n        internal var variableName: String? = null\n        internal var startPosition: Int = 0\n        internal var endPosition: Int = 0\n    }\n\n    companion object {\n        val JLS8 = 8\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AvoidAccessStaticViaInstanceRule.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.pmd.rule\n\nimport net.sourceforge.pmd.RuleContext\nimport org.eclipse.jdt.core.dom.ASTVisitor\nimport org.eclipse.jdt.core.dom.ClassInstanceCreation\nimport org.eclipse.jdt.core.dom.CompilationUnit\nimport org.eclipse.jdt.core.dom.FieldAccess\nimport org.eclipse.jdt.core.dom.IVariableBinding\nimport org.eclipse.jdt.core.dom.MethodInvocation\nimport org.eclipse.jdt.core.dom.Modifier\nimport org.eclipse.jdt.core.dom.QualifiedName\nimport org.eclipse.jdt.core.dom.SimpleName\nimport org.eclipse.jdt.core.dom.VariableDeclarationFragment\n\n/**\n * @author caikang\n * @date 2016/12/27\n */\nclass AvoidAccessStaticViaInstanceRule : AbstractEclipseRule() {\n    override fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor {\n        return object : ASTVisitor() {\n            override fun visit(node: QualifiedName?): Boolean {\n                val parent = node!!.parent\n                if (parent !is MethodInvocation && parent !is VariableDeclarationFragment) {\n                    return false\n                }\n                val name = node.name\n                val binding = name.resolveBinding()\n                if (binding !is IVariableBinding || binding.getModifiers() and Modifier.STATIC == 0) {\n                    return true\n                }\n                val qualifier = node.qualifier\n                val typeBinding = qualifier.resolveTypeBinding()\n                if (qualifier.isSimpleName) {\n                    when (parent) {\n                        is MethodInvocation -> {\n                            val methodBinding = parent.resolveMethodBinding()\n                            val methodTypeBinding = methodBinding.declaringClass\n                            if (methodBinding.modifiers and Modifier.STATIC != 0\n                                    && qualifier.fullyQualifiedName != methodTypeBinding.name\n                                    && methodTypeBinding == typeBinding && binding.name != typeBinding.name) {\n                                violation(ruleContext, parent, ast)\n                                return false\n                            }\n                        }\n                        else -> {\n                        }\n                    }\n                    if (typeBinding.name != qualifier.fullyQualifiedName) {\n                        violation(ruleContext, node, ast)\n                        return false\n                    }\n                }\n                if (qualifier.isQualifiedName) {\n                    val qualifiedName = qualifier as QualifiedName\n                    if (typeBinding.name != qualifiedName.name.identifier) {\n                        violation(ruleContext, node, ast)\n                        return false\n                    }\n                }\n                return true\n            }\n\n            override fun visit(node: FieldAccess): Boolean {\n                val variableBinding = node.resolveFieldBinding() ?: return false\n                if (variableBinding.modifiers and Modifier.STATIC == 0) {\n                    return true\n                }\n                if (node.expression is ClassInstanceCreation) {\n                    violation(ruleContext, node, ast)\n                    return true\n                }\n                return true\n            }\n\n            override fun visit(node: MethodInvocation?): Boolean {\n                val methodBinding = node?.resolveMethodBinding() ?: return false\n                if (methodBinding.modifiers and Modifier.STATIC == 0) {\n                    return true\n                }\n                if (node.expression is ClassInstanceCreation) {\n                    violation(ruleContext, node, ast)\n                    return true\n                }\n                val expression = node.expression\n                if (expression is SimpleName && expression.identifier != expression.resolveTypeBinding().name) {\n                    violation(ruleContext, node, ast)\n                    return true\n                }\n                return true\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AvoidUseDeprecationRule.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.pmd.rule\n\nimport net.sourceforge.pmd.RuleContext\nimport org.eclipse.jdt.core.dom.ASTVisitor\nimport org.eclipse.jdt.core.dom.ClassInstanceCreation\nimport org.eclipse.jdt.core.dom.CompilationUnit\nimport org.eclipse.jdt.core.dom.FieldAccess\nimport org.eclipse.jdt.core.dom.IVariableBinding\nimport org.eclipse.jdt.core.dom.ImportDeclaration\nimport org.eclipse.jdt.core.dom.MethodInvocation\nimport org.eclipse.jdt.core.dom.Modifier\nimport org.eclipse.jdt.core.dom.QualifiedName\nimport org.eclipse.jdt.core.dom.TypeDeclaration\nimport org.eclipse.jdt.core.dom.VariableDeclarationFragment\n\n/**\n * @author caikang\n * @date 2016/12/27\n */\nclass AvoidUseDeprecationRule : AbstractEclipseRule() {\n    override fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor {\n        return object : ASTVisitor() {\n            override fun visit(node: ImportDeclaration?): Boolean {\n                if (node!!.resolveBinding() != null && node.resolveBinding().isDeprecated) {\n                    violation(ruleContext, node, ast)\n                }\n                return true\n            }\n\n            override fun visit(node: QualifiedName?): Boolean {\n                if (node!!.parent !is MethodInvocation && node.parent !is VariableDeclarationFragment) {\n                    return false\n                }\n                val name = node.name\n                val binding = name.resolveBinding()\n                if (binding !is IVariableBinding || binding.getModifiers() and Modifier.STATIC == 0) {\n                    return true\n                }\n                if (binding.isDeprecated()) {\n                    violation(ruleContext, node, ast)\n                    return false\n                }\n                val qualifier = node.qualifier\n                val typeBinding = qualifier.resolveTypeBinding()\n                if (typeBinding.isDeprecated) {\n                    violation(ruleContext, node, ast)\n                    return false\n                }\n                return true\n            }\n\n            override fun visit(node: TypeDeclaration?): Boolean {\n                val superClass = node!!.superclassType\n                if (superClass != null && superClass.resolveBinding().isDeprecated) {\n                    violation(ruleContext, node, ast)\n                    return true\n                }\n                val interfaces = node.resolveBinding().interfaces\n                for (tb in interfaces) {\n                    if (tb.isDeprecated) {\n                        violation(ruleContext, node, ast)\n                        return true\n                    }\n                }\n                return true\n            }\n\n            override fun visit(node: FieldAccess?): Boolean {\n                val variableBinding = node!!.resolveFieldBinding() ?: return false\n                if (variableBinding.isDeprecated) {\n                    violation(ruleContext, node, ast)\n                }\n                return true\n            }\n\n            override fun visit(node: MethodInvocation): Boolean {\n                val methodBinding = node.resolveMethodBinding() ?: return false\n                if (methodBinding.isDeprecated) {\n                    violation(ruleContext, node, ast)\n                }\n                return true\n            }\n\n            override fun visit(node: ClassInstanceCreation?): Boolean {\n                if (node!!.resolveTypeBinding().isDeprecated) {\n                    violation(ruleContext, node, ast)\n                }\n                return true\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/MapOrSetKeyShouldOverrideHashCodeEqualsRule.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.pmd.rule\n\nimport net.sourceforge.pmd.RuleContext\nimport org.eclipse.jdt.core.dom.ASTVisitor\nimport org.eclipse.jdt.core.dom.CompilationUnit\nimport org.eclipse.jdt.core.dom.ITypeBinding\nimport org.eclipse.jdt.core.dom.MethodInvocation\nimport org.eclipse.jdt.core.dom.VariableDeclarationStatement\n\n/**\n * @author zenghou.fw\n * @date 2016/12/27\n */\nclass MapOrSetKeyShouldOverrideHashCodeEqualsRule : AbstractEclipseRule() {\n\n    val methodEquals = \"equals\"\n    val methodHashCode = \"hashCode\"\n    val methodAdd = \"add\"\n    val methodPut = \"put\"\n\n    private val skipJdkPackageJava = \"java.\"\n    private val skipJdkPackageJavax = \"javax.\"\n\n    override fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor {\n        return object : ASTVisitor() {\n\n            override fun visit(node: VariableDeclarationStatement): Boolean {\n                if (!node.type.isParameterizedType) {\n                    return true\n                }\n                val typeBinding = node.type.resolveBinding()\n                if (isSet(typeBinding) || isMap(typeBinding)) {\n                    val argumentTypes = typeBinding.typeArguments\n                    if (argumentTypes != null && argumentTypes.isNotEmpty()) {\n                        if (!isOverrideEqualsAndHashCode(argumentTypes[0])) {\n                            violation(ruleContext, node, ast)\n                            return false\n                        }\n                    }\n                }\n                return true\n            }\n\n            override fun visit(node: MethodInvocation): Boolean {\n                val methodBinding = node.resolveMethodBinding() ?: return false\n                val callerType = methodBinding.declaringClass\n\n                if (methodAdd == methodBinding.name) {\n                    if (!isSet(callerType)) {\n                        return true\n                    }\n                    val parameterTypes = methodBinding.parameterTypes\n                    if (parameterTypes != null && parameterTypes.isNotEmpty()) {\n                        if (!isOverrideEqualsAndHashCode(parameterTypes[0])) {\n                            violation(ruleContext, node, ast)\n                            return false\n                        }\n                    }\n                    return true\n                }\n                if (methodPut == methodBinding.name) {\n                    if (!isMap(callerType)) {\n                        return true\n                    }\n                    val parameterTypes = methodBinding.parameterTypes\n                    if (parameterTypes != null && parameterTypes.isNotEmpty()) {\n                        if (!isOverrideEqualsAndHashCode(parameterTypes[0])) {\n                            violation(ruleContext, node, ast)\n                            return false\n                        }\n                    }\n                }\n                return true\n            }\n\n            private fun isOverrideEqualsAndHashCode(genericType: ITypeBinding): Boolean {\n                val skip = genericType.isEnum || genericType.isInterface || genericType.isArray\n                        || genericType.isTypeVariable || genericType.isWildcardType\n                        || genericType.qualifiedName?.startsWith(skipJdkPackageJava) ?: false\n                        || genericType.qualifiedName?.startsWith(skipJdkPackageJavax) ?: false\n                // skip\n                if (skip) {\n                    return true\n                }\n\n                val methodBindings = genericType.declaredMethods ?: return false\n\n                val overrideCount = methodBindings.asSequence().filter {\n                    //find equals(Object o) and hashCode() with @Override\n                    methodEquals == it.name || methodHashCode == it.name\n                }.filter {\n                    when (it.name) {\n                        methodEquals -> {\n                            val parameterTypes = it.parameterTypes\n                            parameterTypes != null && parameterTypes.isNotEmpty()\n                                    && Object::class.java.name == parameterTypes[0].qualifiedName\n                        }\n                        methodHashCode -> {\n                            val parameterTypes = it.parameterTypes\n                            parameterTypes == null || parameterTypes.isEmpty()\n                        }\n                        else -> false\n                    }\n                }.count()\n                return overrideCount == 2\n            }\n\n            private fun isSet(typeBinding: ITypeBinding): Boolean {\n                return java.util.Set::class.java.name == typeBinding.binaryName\n            }\n\n            private fun isMap(typeBinding: ITypeBinding): Boolean {\n                return java.util.Map::class.java.name == typeBinding.binaryName\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/MissingOverrideAnnotationRule.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.pmd.rule\n\nimport com.alibaba.smartfox.eclipse.message.P3cBundle\nimport net.sourceforge.pmd.RuleContext\nimport org.eclipse.jdt.core.dom.ASTVisitor\nimport org.eclipse.jdt.core.dom.CompilationUnit\nimport org.eclipse.jdt.core.dom.MethodDeclaration\nimport org.eclipse.jdt.internal.compiler.lookup.MethodBinding\nimport java.util.Arrays\nimport javax.annotation.Generated\n\n/**\n * @author caikang\n * @date 2016/12/24\n */\nclass MissingOverrideAnnotationRule : AbstractEclipseRule() {\n    override fun getErrorMessage(): String {\n        return P3cBundle.getMessage(\"rule.standalone.MissingOverrideAnnotationRule.error\")\n    }\n\n    override fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor {\n        return MissingOverrideVisitor(ast, ruleContext)\n    }\n\n    private inner class MissingOverrideVisitor(private val ast: CompilationUnit,\n            private val ruleContext: RuleContext) : ASTVisitor() {\n\n        override fun visit(node: MethodDeclaration?): Boolean {\n            val methodBinding = node!!.resolveBinding()\n            val declaringClass = methodBinding.declaringClass ?: return super.visit(node)\n            if (declaringClass.isInterface) {\n                return super.visit(node)\n            }\n            val abs = methodBinding.annotations\n            if (abs.any {\n                Override::class.java.canonicalName == it.annotationType.binaryName\n            }) {\n                return super.visit(node)\n            }\n            try {\n                val field = methodBinding.javaClass.getDeclaredField(\"binding\")\n                field.isAccessible = true\n                val internalBinding = field.get(methodBinding) as MethodBinding\n                if (internalBinding.isStatic || !(internalBinding.isImplementing || internalBinding.isOverriding)\n                        || isGenerated(internalBinding)) {\n                    return super.visit(node)\n                }\n                violation(ruleContext, node, ast)\n            } catch (e: Exception) {\n                e.printStackTrace()\n            }\n\n            return super.visit(node)\n        }\n\n        /**\n         * skip @Override check for generated code by lombok\n         * @param internalBinding\n         * @return\n         */\n        private fun isGenerated(internalBinding: MethodBinding): Boolean {\n            val annotationBindings = internalBinding.annotations ?: return false\n            return annotationBindings.any {\n                it.annotationType != null && Arrays.equals(Generated::class.java.name.toCharArray(),\n                        it.annotationType.readableName())\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/AllRulesPreferencePage.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport org.eclipse.jface.preference.PreferencePage\nimport org.eclipse.swt.widgets.Composite\nimport org.eclipse.swt.widgets.Control\nimport org.eclipse.ui.IWorkbench\nimport org.eclipse.ui.IWorkbenchPreferencePage\n\n/**\n *\n * @author caikang\n * @date 2017/09/01\n */\nclass AllRulesPreferencePage : PreferencePage(), IWorkbenchPreferencePage {\n    override fun init(parent: IWorkbench?) {\n    }\n\n    override fun createContents(parent: Composite): Control {\n        return AllRulesView(parent).content\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/AllRulesView.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport org.eclipse.swt.SWT\nimport org.eclipse.swt.layout.FillLayout\nimport org.eclipse.swt.widgets.Composite\nimport org.eclipse.swt.widgets.List\n\n\n/**\n *\n * @author caikang\n * @date 2017/09/01\n */\nclass AllRulesView(parent: Composite) {\n    val content = Composite(parent, SWT.NONE)\n\n    private val ruleList = SmartfoxActivator.instance.ruleSets.allRules.toList()\n\n    init {\n        content.layout = FillLayout()\n        val list = List(content, SWT.BORDER or SWT.SINGLE or SWT.V_SCROLL or SWT.PUSH or SWT.H_SCROLL)\n        ruleList.forEach {\n            list.add(it.message)\n        }\n        val ruleDetail = RuleDetailComposite(content, SWT.PUSH)\n        list.addListener(SWT.Selection) {\n            val index = list.selectionIndex\n            val rule = ruleList.getOrNull(index) ?: return@addListener\n            ruleDetail.refresh(rule)\n        }\n        list.select(0)\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultTreeContentProvider.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport org.eclipse.jface.viewers.ITreeContentProvider\nimport org.eclipse.jface.viewers.Viewer\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/08\n */\nobject InspectionResultTreeContentProvider : ITreeContentProvider {\n    private lateinit var input: InspectionResults\n\n    override fun getParent(element: Any?): Any {\n        return input\n    }\n\n    override fun hasChildren(element: Any?): Boolean {\n        return element is InspectionResults || element is LevelViolations || element is RuleViolations\n                || element is FileMarkers\n    }\n\n    override fun getChildren(parentElement: Any?): Array<Any> {\n        if (parentElement is InspectionResults) {\n            return parentElement.errors.toTypedArray()\n        }\n        if (parentElement is LevelViolations) {\n            return parentElement.rules.toTypedArray()\n        }\n        if (parentElement is RuleViolations) {\n            return parentElement.files.toTypedArray()\n        }\n        if (parentElement is FileMarkers) {\n            return parentElement.markers.toTypedArray()\n        }\n        return emptyArray()\n    }\n\n    override fun getElements(inputElement: Any?): Array<Any> {\n        return input.errors.toTypedArray()\n    }\n\n    override fun inputChanged(viewer: Viewer?, oldInput: Any?, newInput: Any?) {\n        if (newInput == null) {\n            return\n        }\n        this.input = newInput as InspectionResults\n    }\n\n    override fun dispose() {\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultTreeLabelProvider.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport com.alibaba.smartfox.eclipse.pmd.RulePriority\nimport org.eclipse.jface.viewers.LabelProvider\nimport org.eclipse.swt.graphics.Image\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/08\n */\nobject InspectionResultTreeLabelProvider : LabelProvider() {\n    override fun getImage(element: Any?): Image? {\n        if (element is LevelViolations) {\n            val imageName = when (element.level) {\n                RulePriority.Blocker.title, RulePriority.Critical.title -> \"${element.level}.gif\".toLowerCase()\n                else -> \"${element.level}.png\".toLowerCase()\n            }\n            return SmartfoxActivator.instance.getImage(\"icons/view/$imageName\")\n        }\n        if (element is FileMarkers) {\n            if (element.file.fullPath.toPortableString().endsWith(\"java\")) {\n                return SmartfoxActivator.instance.getImage(\"icons/view/class_obj.png\")\n            }\n            return SmartfoxActivator.instance.getImage(\"icons/view/file_obj.png\")\n        }\n        return null\n    }\n\n    override fun getText(element: Any?): String {\n        if (element is LevelViolations) {\n            return \"${element.level} (${element.count} Violations)\"\n        }\n        if (element is RuleViolations) {\n            val rule = SmartfoxActivator.instance.getRule(element.rule)\n            return \"${rule.message} (${element.count} Violations)\"\n        }\n        if (element is FileMarkers) {\n            return element.file.fullPath.toPortableString().substringAfterLast(\"/\") +\n                    \" (${element.markers.size} Violations)\"\n        }\n        if (element is MarkerViolation) {\n            val desc = element.violation.description\n            return \"$desc (at line ${element.violation.beginLine})\"\n        }\n        return element.toString()\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultView.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport com.alibaba.smartfox.eclipse.job.P3cMutex\nimport com.alibaba.smartfox.eclipse.util.MarkerUtil\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.resources.IMarker\nimport org.eclipse.core.runtime.IProgressMonitor\nimport org.eclipse.core.runtime.IStatus\nimport org.eclipse.core.runtime.Status\nimport org.eclipse.core.runtime.jobs.Job\nimport org.eclipse.jface.action.Action\nimport org.eclipse.jface.action.Separator\nimport org.eclipse.jface.util.OpenStrategy\nimport org.eclipse.jface.viewers.ISelection\nimport org.eclipse.jface.viewers.IStructuredSelection\nimport org.eclipse.jface.viewers.ITreeSelection\nimport org.eclipse.jface.viewers.TreeViewer\nimport org.eclipse.swt.SWT\nimport org.eclipse.swt.layout.FillLayout\nimport org.eclipse.swt.widgets.Composite\nimport org.eclipse.swt.widgets.Display\nimport org.eclipse.ui.IWorkbenchPage\nimport org.eclipse.ui.OpenAndLinkWithEditorHelper\nimport org.eclipse.ui.PartInitException\nimport org.eclipse.ui.PlatformUI\nimport org.eclipse.ui.ide.IDE\nimport org.eclipse.ui.ide.ResourceUtil\nimport org.eclipse.ui.internal.views.markers.MarkerSupportInternalUtilities\nimport org.eclipse.ui.part.ViewPart\nimport org.eclipse.ui.texteditor.ITextEditor\nimport java.util.HashSet\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/08\n */\nclass InspectionResultView : ViewPart() {\n    lateinit var treeViewer: TreeViewer\n\n    private val quickFixAction = QuickFixAction(this)\n\n    override fun setFocus() {\n        treeViewer.control.setFocus()\n    }\n\n    override fun createPartControl(parent: Composite) {\n        parent.layout = FillLayout()\n        treeViewer = TreeViewer(parent, SWT.MULTI or SWT.H_SCROLL or SWT.V_SCROLL)\n        treeViewer.setUseHashlookup(true)\n        treeViewer.contentProvider = InspectionResultTreeContentProvider\n        treeViewer.labelProvider = InspectionResultTreeLabelProvider\n        treeViewer.input = InspectionResults\n\n        InspectionResults.view = this\n\n        addDoubleClickListener()\n\n        addSelectionChangedListener()\n\n        initToolBar()\n\n        addLinkWithEditorSupport()\n        site.selectionProvider = treeViewer\n    }\n\n    fun clear() {\n        InspectionResults.clear()\n        refreshView(InspectionResults)\n    }\n\n    fun refreshView(input: InspectionResults) {\n        Display.getDefault().asyncExec {\n            treeViewer.refresh(input, true)\n            contentDescription = input.contentDescription\n        }\n    }\n\n    private fun addSelectionChangedListener() {\n        treeViewer.addSelectionChangedListener inner@ {\n            val selection = it.selection as? IStructuredSelection ?: return@inner\n            val item = selection.firstElement ?: return@inner\n            val ruleDetailView = RuleDetailView.showAndGetView()\n            when (item) {\n                is MarkerViolation -> {\n                    ruleDetailView.refresh(item.violation.rule)\n                    quickFixAction.updateFileMarkers(listOf(FileMarkers(item.marker.resource as IFile, listOf(item))))\n                }\n                is FileMarkers -> {\n                    ruleDetailView.refresh(item.markers.first().violation.rule)\n                    quickFixAction.updateFileMarkers(listOf(item))\n                }\n                is RuleViolations -> {\n                    ruleDetailView.refresh(SmartfoxActivator.instance.getRule(item.rule))\n                    quickFixAction.updateFileMarkers(item.files)\n                }\n                else -> {\n                    quickFixAction.updateFileMarkers(emptyList())\n                }\n            }\n        }\n    }\n\n    private fun initToolBar() {\n        val bars = viewSite.actionBars\n        val tm = bars.toolBarManager\n\n        val clearAction = object : Action(\"Clear Markers\") {\n            override fun run() {\n                val job = object : Job(\"Clear Markers\") {\n                    override fun run(monitor: IProgressMonitor): IStatus {\n                        if (monitor.isCanceled) {\n                            Status.CANCEL_STATUS\n                        }\n                        clear()\n                        return Status.OK_STATUS\n                    }\n                }\n                job.rule = P3cMutex\n                job.schedule()\n            }\n        }\n\n        clearAction.imageDescriptor = SmartfoxActivator.getImageDescriptor(\"icons/actions/clear.png\")\n\n        tm.add(Separator(\"Markers\"))\n        tm.add(clearAction)\n\n        tm.add(Separator(\"FilterGroup\"))\n        tm.add(quickFixAction)\n    }\n\n    private fun addLinkWithEditorSupport() {\n        object : OpenAndLinkWithEditorHelper(treeViewer) {\n            override fun activate(selection: ISelection) {\n                val currentMode = OpenStrategy.getOpenMethod()\n                try {\n                    OpenStrategy.setOpenMethod(OpenStrategy.DOUBLE_CLICK)\n                    openSelectedMarkers()\n                } finally {\n                    OpenStrategy.setOpenMethod(currentMode)\n                }\n            }\n\n            override fun linkToEditor(selection: ISelection?) {\n            }\n\n            override fun open(selection: ISelection, activate: Boolean) {\n                val structured = selection as ITreeSelection\n                val element = structured.firstElement as? MarkerViolation ?: return\n                val page = site.page\n                if (element.marker.exists()) {\n                    openMarkerInEditor(element.marker, page)\n                    return\n                }\n                val file = element.marker.resource as IFile\n                val editor = IDE.openEditor(page, file) as ITextEditor\n                editor.selectAndReveal(MarkerUtil.getAbsoluteRange(file, element.violation).start, 0)\n            }\n        }\n    }\n\n    internal fun openSelectedMarkers() {\n        val markers = getOpenableMarkers()\n        for (marker in markers) {\n            val page = site.page\n            openMarkerInEditor(marker, page)\n        }\n    }\n\n    private fun getOpenableMarkers(): Array<IMarker> {\n        val structured = treeViewer.selection as ITreeSelection\n        val elements = structured.iterator()\n        val result = HashSet<IMarker>()\n\n        while (elements.hasNext()) {\n            val marker = elements.next() as? IMarker ?: return emptyArray()\n            result.add(marker)\n        }\n        return result.toTypedArray()\n    }\n\n\n    fun openMarkerInEditor(marker: IMarker?, page: IWorkbenchPage) {\n        val editor = page.activeEditor\n        if (editor != null) {\n            val input = editor.editorInput\n            val file = ResourceUtil.getFile(input)\n            if (file != null) {\n                if (marker!!.resource == file && OpenStrategy.activateOnOpen()) {\n                    page.activate(editor)\n                }\n            }\n        }\n\n        if (marker != null && marker.resource is IFile) {\n            try {\n                IDE.openEditor(page, marker, OpenStrategy.activateOnOpen())\n            } catch (e: PartInitException) {\n                MarkerSupportInternalUtilities.showViewError(e)\n            }\n\n        }\n    }\n\n    private fun addDoubleClickListener() {\n        treeViewer.addDoubleClickListener({ event ->\n            val selection = event.selection\n            if (selection !is ITreeSelection || selection.size() != 1) {\n                return@addDoubleClickListener\n            }\n            val obj = selection.firstElement\n            if (treeViewer.isExpandable(obj)) {\n                treeViewer.setExpandedState(obj, !treeViewer.getExpandedState(obj))\n            }\n        })\n    }\n\n    companion object {\n        val viewId = \"com.alibaba.smartfox.eclipse.ui.InspectionResultView\"\n\n        fun activeViews() {\n            PlatformUI.getWorkbench().activeWorkbenchWindow.activePage.showView(viewId)\n            RuleDetailView.showAndGetView()\n        }\n\n        fun getView(): InspectionResultView {\n            return PlatformUI.getWorkbench().activeWorkbenchWindow.activePage.findView(viewId) as InspectionResultView\n        }\n    }\n}\n\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResults.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport com.alibaba.smartfox.eclipse.pmd.RulePriority\nimport com.alibaba.smartfox.eclipse.util.MarkerUtil\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.resources.IMarker\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/13\n */\nobject InspectionResults {\n    private val fileViolations = linkedMapOf<IFile, List<MarkerViolation>>()\n\n    var contentDescription = \"\"\n\n    val errors: List<LevelViolations>\n        get() {\n            val result = toLevelViolationList(fileViolations.values.flatten())\n            contentDescription = getContentDescription(result)\n            return result\n        }\n\n    lateinit var view: InspectionResultView\n\n\n    fun clear() {\n        fileViolations.forEach {\n            MarkerUtil.removeAllMarkers(it.key)\n        }\n        fileViolations.clear()\n        // update contentDescription\n        errors\n    }\n\n    private fun toLevelViolationList(markers: Collection<MarkerViolation>): List<LevelViolations> {\n        return markers.groupBy {\n            it.violation.rule.priority.priority\n        }.mapValues {\n            it.value.groupBy {\n                it.violation.rule.name\n            }.mapValues {\n                it.value.groupBy {\n                    it.marker.resource as IFile\n                }.map {\n                    FileMarkers(it.key, it.value)\n                }\n            }.map {\n                RuleViolations(it.key, it.value)\n            }\n        }.toSortedMap().map {\n            val level = RulePriority.valueOf(it.key).title\n            LevelViolations(level, it.value)\n        }\n    }\n\n    fun updateFileViolations(file: IFile, markers: List<MarkerViolation>) {\n        if (markers.isEmpty()) {\n            fileViolations.remove(file)\n        } else {\n            fileViolations[file] = markers\n        }\n        view.refreshView(this)\n    }\n\n    fun removeMarker(marker: IMarker) {\n        val file = marker.resource as IFile\n        val list = fileViolations[file] ?: return\n        val result = list.filter {\n            it.marker != marker\n        }\n        fileViolations[file] = result\n        marker.delete()\n        view.refreshView(this)\n    }\n\n    fun getContentDescription(errors: List<LevelViolations>): String {\n        val map = errors.associateBy {\n            it.level\n        }\n\n        return \"${map[RulePriority.Blocker.title]?.count ?: 0} Blockers,\" +\n                \"${map[RulePriority.Critical.title]?.count ?: 0} Criticals,\" +\n                \"${map[RulePriority.Major.title]?.count ?: 0} Majors\"\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/QuickFixAction.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport com.alibaba.p3c.pmd.lang.java.rule.flowcontrol.NeedBraceRule\nimport com.alibaba.smartfox.eclipse.RunWithoutViewRefresh\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport com.alibaba.smartfox.eclipse.job.CodeAnalysis\nimport com.alibaba.smartfox.eclipse.job.P3cMutex\nimport com.alibaba.smartfox.eclipse.pmd.rule.MissingOverrideAnnotationRule\nimport com.alibaba.smartfox.eclipse.util.CleanUps\nimport com.alibaba.smartfox.eclipse.util.getResolution\nimport org.eclipse.core.runtime.IProgressMonitor\nimport org.eclipse.core.runtime.IStatus\nimport org.eclipse.core.runtime.Status\nimport org.eclipse.core.runtime.SubMonitor\nimport org.eclipse.core.runtime.jobs.Job\nimport org.eclipse.jface.action.Action\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/14\n */\nclass QuickFixAction(val view: InspectionResultView) : Action(\"Quick Fix\") {\n    init {\n        imageDescriptor = SmartfoxActivator.getImageDescriptor(\"icons/actions/quickfixBulb.png\")\n        isEnabled = false\n    }\n\n    var markers = listOf<FileMarkers>()\n\n    fun updateFileMarkers(markers: List<FileMarkers>) {\n        this.markers = markers\n        isEnabled = enabled()\n    }\n\n    override fun run() {\n        if (markers.isEmpty()) {\n            return\n        }\n        runJob()\n    }\n\n    private fun runJob() {\n        val job = object : Job(\"Perform P3C Quick Fix\") {\n            override fun run(monitor: IProgressMonitor): IStatus {\n                val subMonitor = SubMonitor.convert(monitor, markers.size)\n                monitor.setTaskName(\"Process File\")\n                markers.forEach {\n                    if (monitor.isCanceled) {\n                        return@run Status.CANCEL_STATUS\n                    }\n                    monitor.subTask(it.file.name)\n                    val childMonitor = subMonitor.newChild(1)\n                    if (useCleanUpRefactoring()) {\n                        CleanUps.fix(it.file, childMonitor)\n                    } else {\n                        it.markers.filter { it.marker.exists() }.forEach {\n                            (it.marker.getResolution() as RunWithoutViewRefresh).run(it.marker, true)\n                        }\n                    }\n                    val markers = CodeAnalysis.processFileToMakers(it.file, monitor)\n                    InspectionResults.updateFileViolations(it.file, markers)\n                }\n\n                return Status.OK_STATUS\n            }\n        }\n        val outJob = object:Job(\"P3C Quick Fix Wait analysis finish\"){\n            override fun run(monitor: IProgressMonitor?): IStatus {\n                job.schedule()\n                return Status.OK_STATUS\n            }\n        }\n        outJob.rule = P3cMutex\n        outJob.schedule()\n\n    }\n\n    fun enabled(): Boolean {\n        if (useCleanUpRefactoring()) {\n            return true\n        }\n        if (markers.isEmpty()) {\n            return false\n        }\n        val marker = markers.first().markers.first().marker\n        return marker.exists() && marker.getResolution() != null\n    }\n\n    private fun useCleanUpRefactoring(): Boolean {\n        if (markers.isEmpty()) {\n            return false\n        }\n        val ruleName = markers.first().markers.first().violation.rule.name\n        return ruleName == MissingOverrideAnnotationRule::class.java.simpleName\n                || ruleName == NeedBraceRule::class.java.simpleName\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/RuleDetailComposite.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport com.alibaba.smartfox.eclipse.pmd.RulePriority\nimport com.alibaba.smartfox.eclipse.ui.pmd.ContentBuilder\nimport com.alibaba.smartfox.eclipse.ui.pmd.StringArranger\nimport net.sourceforge.pmd.Rule\nimport org.eclipse.swt.SWT\nimport org.eclipse.swt.custom.StyledText\nimport org.eclipse.swt.layout.FillLayout\nimport org.eclipse.swt.widgets.Composite\n\n/**\n *\n * @author caikang\n * @date 2017/09/01\n */\nclass RuleDetailComposite(parent: Composite, style: Int = SWT.NONE) {\n    private val viewField: StyledText\n    private val contentBuilder = ContentBuilder()\n    private val arranger = StringArranger(\"   \")\n    private val panel = Composite(parent, style)\n\n    init {\n        panel.layout = FillLayout()\n\n        viewField = StyledText(panel, SWT.BORDER or SWT.H_SCROLL or SWT.V_SCROLL)\n        viewField.wordWrap = true\n        viewField.tabs = 20\n        viewField.text = \"Select a result item to show rule detail.\"\n        viewField.editable = false\n    }\n\n    fun refresh(rule: Rule) {\n        contentBuilder.clear()\n        viewField.text = \"\"\n        contentBuilder.addHeading(\"Name\")\n        contentBuilder.addText(rule.name)\n        contentBuilder.addHeading(\"Severity\")\n        contentBuilder.addText(RulePriority.valueOf(rule.priority.priority).title)\n        contentBuilder.addHeading(\"Message\")\n        contentBuilder.addText(rule.message)\n        if (!rule.description.isNullOrBlank()) {\n            contentBuilder.addHeading(\"Description\")\n            contentBuilder.addRawText(arranger.format(rule.description).toString())\n        }\n\n        val examples = rule.examples\n        if (examples.isEmpty()) {\n            contentBuilder.showOn(viewField)\n            return\n        }\n\n        contentBuilder.setLanguage(rule.language)\n\n        contentBuilder.addHeading(\"Examples\")\n        contentBuilder.addText(\"\")\n        for (example in rule.examples) {\n            contentBuilder.addCode(example.trim { it <= ' ' })\n            contentBuilder.addText(\"\")\n        }\n        contentBuilder.showOn(viewField)\n\n        if (contentBuilder.hasLinks()) {\n            contentBuilder.addLinkHandler(viewField)\n        }\n        viewField.update()\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/RuleDetailView.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport net.sourceforge.pmd.Rule\nimport org.eclipse.jface.action.Action\nimport org.eclipse.jface.action.Separator\nimport org.eclipse.swt.SWT\nimport org.eclipse.swt.custom.ScrolledComposite\nimport org.eclipse.swt.layout.FillLayout\nimport org.eclipse.swt.widgets.Composite\nimport org.eclipse.swt.widgets.Display\nimport org.eclipse.swt.widgets.Shell\nimport org.eclipse.ui.IWorkbenchPage\nimport org.eclipse.ui.PlatformUI\nimport org.eclipse.ui.part.ViewPart\n\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/12\n */\nopen class RuleDetailView : ViewPart() {\n\n    private lateinit var ruleDetailComposite: RuleDetailComposite\n\n    override fun setFocus() {\n    }\n\n    override fun createPartControl(parent: Composite) {\n        ruleDetailComposite = RuleDetailComposite(parent)\n        initToolBar()\n    }\n\n    fun refresh(rule: Rule) {\n        ruleDetailComposite.refresh(rule)\n    }\n\n\n    private fun initToolBar() {\n        val bars = viewSite.actionBars\n        val tm = bars.toolBarManager\n\n        val rulesAction = object : Action(\"Show Rules\") {\n            override fun run() {\n                val shell = Shell(Display.getDefault())\n                shell.text = \"All Rules\"\n                shell.layout = FillLayout()\n\n                val sc = ScrolledComposite(shell, SWT.V_SCROLL or SWT.H_SCROLL)\n\n                val rulesView = AllRulesView(sc)\n\n                sc.expandHorizontal = true\n                sc.expandVertical = true\n\n                sc.content = rulesView.content\n\n                shell.open()\n            }\n        }\n\n        rulesAction.imageDescriptor = SmartfoxActivator.getImageDescriptor(\"icons/actions/rules.png\")\n\n        tm.add(Separator(\"Markers\"))\n        tm.add(rulesAction)\n    }\n\n    companion object {\n        fun showAndGetView(): RuleDetailView {\n            return PlatformUI.getWorkbench().activeWorkbenchWindow.activePage.showView(\n                    \"com.alibaba.smartfox.eclipse.ui.RuleDetailView\", null,\n                    IWorkbenchPage.VIEW_VISIBLE) as RuleDetailView\n        }\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/Violations.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.eclipse.ui\n\nimport com.alibaba.smartfox.eclipse.util.MarkerUtil\nimport net.sourceforge.pmd.RuleViolation\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.resources.IMarker\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/13\n */\ndata class LevelViolations(var level: String, var rules: List<RuleViolations>,\n        var count: Int = rules.sumBy { it.count }) {\n    fun removeMarkers() {\n        rules.forEach {\n            it.removeMarkers()\n        }\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other !is LevelViolations) {\n            return false\n        }\n        return level == other.level\n    }\n\n    override fun hashCode(): Int {\n        return level.hashCode()\n    }\n}\n\ndata class RuleViolations(var rule: String, var files: List<FileMarkers>,\n        var count: Int = files.sumBy { it.markers.size }) {\n    fun removeMarkers() {\n        files.forEach {\n            it.removeMarkers()\n        }\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other !is RuleViolations) {\n            return false\n        }\n        return rule == other.rule\n    }\n\n    override fun hashCode(): Int {\n        return rule.hashCode()\n    }\n}\n\ndata class FileMarkers(var file: IFile, var markers: List<MarkerViolation>) {\n    fun removeMarkers() {\n        MarkerUtil.removeAllMarkers(file)\n    }\n\n    override fun equals(other: Any?): Boolean {\n        if (other !is FileMarkers) {\n            return false\n        }\n        return file == other.file\n    }\n\n    override fun hashCode(): Int {\n        return file.hashCode()\n    }\n}\n\ndata class MarkerViolation(val marker: IMarker, val violation: RuleViolation)\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/BasicLineStyleListener.kt",
    "content": "package com.alibaba.smartfox.eclipse.ui.pmd\n\nimport org.eclipse.swt.custom.LineStyleEvent\nimport org.eclipse.swt.custom.LineStyleListener\n\n/**\n * This class performs the syntax highlighting and styling for Pmpe\n *  * PmpeLineStyleListener constructor\n\n * @param theSyntaxData the syntax data to use\n */\nclass BasicLineStyleListener(theSyntaxData: SyntaxData) : StyleExtractor(theSyntaxData), LineStyleListener {\n    /**\n     * Called by StyledText to get styles for a line\n     */\n    override fun lineGetStyle(event: LineStyleEvent) {\n        val styles = lineStylesFor(event.lineText, event.lineOffset, event.lineText.length)\n        event.styles = styles.toTypedArray()\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/ContentBuilder.kt",
    "content": "package com.alibaba.smartfox.eclipse.ui.pmd\n\nimport net.sourceforge.pmd.lang.Language\nimport org.eclipse.swt.SWT\nimport org.eclipse.swt.custom.StyleRange\nimport org.eclipse.swt.custom.StyledText\nimport org.eclipse.swt.graphics.Point\nimport org.eclipse.swt.widgets.Display\nimport org.eclipse.ui.PlatformUI\nimport java.net.URL\nimport java.util.ArrayList\nimport java.util.Arrays\nimport java.util.HashMap\n\n/**\n *\n * @author caikang\n * @date 2017/07/20\n */\nclass ContentBuilder {\n    private val CR = '\\n'\n    private val buffer = StringBuilder()\n    private val headingSpans = ArrayList<IntArray>()\n    private val codeSpans = ArrayList<IntArray>()\n    private val linksBySpan = HashMap<IntArray, String>()\n\n    private val indentDepth: Int = 3\n\n    private val codeStyleExtractor = StyleExtractor(SyntaxManager.getSyntaxData(\"java\"))\n\n    private val background = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)\n\n    private val headingColor = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)\n\n    private val codeStyle = FontBuilder(\"Courier\", 11, SWT.NORMAL).style(Display.getCurrent())\n\n    fun clear() {\n        buffer.setLength(0)\n        headingSpans.clear()\n        codeSpans.clear()\n        linksBySpan.clear()\n    }\n\n    fun addHeading(heading: String) {\n        var length = buffer.length\n        if (length > 0) {\n            buffer.append(CR)\n            length += 1\n        }\n\n        headingSpans.add(intArrayOf(length, length + heading.length))\n        buffer.append(heading).append(CR)\n    }\n\n    fun addText(text: String) {\n        for (i in 0 until indentDepth) {\n            buffer.append(' ')\n        }\n        buffer.append(text).append(CR)\n    }\n\n    fun addRawText(text: String) {\n        buffer.append(text)\n    }\n\n    fun addCode(code: String) {\n        val length = buffer.length\n        codeSpans.add(intArrayOf(length, length + code.length))\n        buffer.append(code)\n    }\n\n    fun setLanguage(language: Language) {\n        val syntax = SyntaxManager.getSyntaxData(language.terseName)\n        codeStyleExtractor.syntax(syntax)\n    }\n\n    fun hasLinks(): Boolean {\n        return linksBySpan.isNotEmpty()\n    }\n\n    fun addLinkHandler(widget: StyledText) {\n\n        widget.addListener(SWT.MouseDown) { event ->\n            // It is up to the application to determine when and how a link\n            // should be activated.\n            // In this snippet links are activated on mouse down when the\n            // control key is held down\n            // if ((event.stateMask & SWT.MOD1) != 0) {\n            try {\n                val offset = widget.getOffsetAtLocation(Point(event.x, event.y))\n                val link = linkAt(offset)\n                if (link != null) {\n                    launchBrowser(link)\n                }\n\n            } catch (e: IllegalArgumentException) {\n                // no character under event.x, event.y\n            }\n        }\n    }\n\n    private fun linkAt(textIndex: Int): String? {\n        var span: IntArray\n        for ((key, value) in linksBySpan) {\n            span = key\n            if (span[0] <= textIndex && textIndex <= span[1]) {\n                return value\n            }\n        }\n        return null\n    }\n\n    private fun launchBrowser(link: String) {\n        try {\n            val browser = PlatformUI.getWorkbench().browserSupport.externalBrowser\n            browser.openURL(URL(link))\n        } catch (ex: Exception) {\n            ex.printStackTrace()\n        }\n    }\n\n    fun showOn(widget: StyledText) {\n        val text = buffer.toString()\n        widget.text = text\n        val ranges = ArrayList<StyleRange>()\n        var span: IntArray\n        for (i in headingSpans.indices) {\n            span = headingSpans[i]\n            ranges.add(StyleRange(span[0], span[1] - span[0], headingColor, background, SWT.BOLD))\n        }\n        for (spn in linksBySpan.keys) {\n            val style = StyleRange(spn[0], spn[1] - spn[0], headingColor, background, SWT.UNDERLINE_LINK)\n            style.underline = true\n            ranges.add(style)\n        }\n        val crStr = Character.toString(CR)\n        var sr: StyleRange\n\n        for (i in codeSpans.indices) {\n            span = codeSpans[i]\n            sr = StyleRange(codeStyle)\n            sr.start = span[0]\n            sr.length = span[1] - span[0]\n\n            val colorRanges = codeStyleExtractor.stylesFor(text, sr.start, sr.length, crStr)\n            ranges += colorRanges\n        }\n        // must be in order!\n        val styles = sort(ranges)\n        widget.styleRanges = styles\n    }\n\n    private fun sort(ranges: List<StyleRange>): Array<StyleRange> {\n        val styles = ranges.toTypedArray()\n        Arrays.sort(styles) { sr1, sr2 -> sr1.start - sr2.start }\n        return styles\n    }\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/FontBuilder.kt",
    "content": "package com.alibaba.smartfox.eclipse.ui.pmd\n\nimport org.eclipse.swt.graphics.Font\nimport org.eclipse.swt.graphics.TextStyle\nimport org.eclipse.swt.widgets.Display\n\n/**\n * @author Brian Remedios\n */\nclass FontBuilder(val name: String, val size: Int, val style: Int, val colorIdx: Int = -1) {\n\n    fun build(display: Display): Font {\n        return Font(display, name, size, style)\n    }\n\n    fun style(display: Display): TextStyle {\n        return TextStyle(build(display), if (colorIdx < 0) null else display.getSystemColor(colorIdx), null)\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/StringArranger.kt",
    "content": "package com.alibaba.smartfox.eclipse.ui.pmd\n\nimport net.sourceforge.pmd.util.StringUtil\nimport java.util.ArrayList\n\n/**\n * @author Brian Remedios\n */\nclass StringArranger(private val indentString: String) {\n\n    fun withIndent(rawText: String): String {\n        return indentString + rawText\n    }\n\n    fun format(rawText: String): StringBuilder {\n\n        val sb = StringBuilder()\n        for (line in trimmedLinesIn(rawText)) {\n            sb.append(indentString)\n            sb.append(line).append(CR)\n        }\n\n        return sb\n    }\n\n    fun trimmedLinesIn(text: String): List<String> {\n\n        val lines = text.split(\"\\n\".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()\n        if (lines.isEmpty()) {\n            return emptyList()\n        }\n\n        val lineSet = ArrayList<String>(lines.size)\n\n        var startLine = 0\n        while (startLine < lines.size && StringUtil.isEmpty(lines[startLine])) {\n            startLine++\n        }\n\n        var endLine = lines.size - 1\n        while (endLine >= 0 && StringUtil.isEmpty(lines[endLine])) {\n            endLine--\n        }\n\n        lines.mapTo(lineSet) {\n            it.trim { it <= ' ' }\n        }\n        return lineSet\n    }\n\n    companion object {\n        private val CR = '\\n'\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/StyleExtractor.kt",
    "content": "package com.alibaba.smartfox.eclipse.ui.pmd\n\nimport net.sourceforge.pmd.util.StringUtil\nimport org.eclipse.swt.SWT\nimport org.eclipse.swt.custom.StyleRange\nimport org.eclipse.swt.widgets.Display\nimport java.util.ArrayList\nimport java.util.LinkedList\n\n/**\n * @author Brian Remedios\n */\nopen class StyleExtractor(private var syntaxData: SyntaxData?) {\n    private val commentOffsets: MutableList<IntArray>\n\n    init {\n        commentOffsets = LinkedList<IntArray>()\n    }\n\n    fun syntax(theSyntax: SyntaxData?) {\n        syntaxData = theSyntax\n    }\n\n    /**\n     * Refreshes the offsets for all multiline comments in the parent\n     * StyledText. The parent StyledText should call this whenever its text is\n     * modified. Note that this code doesn't ignore comment markers inside\n     * strings.\n\n     * @param text the text from the StyledText\n     */\n    fun refreshMultilineComments(text: String) {\n        // Clear any stored offsets\n        commentOffsets.clear()\n\n        if (syntaxData != null) {\n            // Go through all the instances of COMMENT_START\n            var pos = text.indexOf(syntaxData!!.multiLineCommentStart!!)\n            while (pos > -1) {\n                // offsets[0] holds the COMMENT_START offset\n                // and COMMENT_END holds the ending offset\n                val offsets = IntArray(2)\n                offsets[0] = pos\n\n                // Find the corresponding end comment.\n                pos = text.indexOf(syntaxData!!.multiLineCommentEnd!!, pos)\n\n                // If no corresponding end comment, use the end of the text\n                offsets[1] = if (pos == -1) text.length - 1 else pos + syntaxData!!.multiLineCommentEnd!!.length - 1\n                pos = offsets[1]\n                // Add the offsets to the collection\n                commentOffsets.add(offsets)\n                pos = text.indexOf(syntaxData!!.multiLineCommentStart!!, pos)\n            }\n        }\n    }\n\n    /**\n     * Checks to see if the specified section of text begins inside a multiline\n     * comment. Returns the index of the closing comment, or the end of the line\n     * if the whole line is inside the comment. Returns -1 if the line doesn't\n     * begin inside a comment.\n\n     * @param start the starting offset of the text\n     * @param length the length of the text\n     * @return int\n     */\n    private fun getBeginsInsideComment(start: Int, length: Int): Int {\n        // Assume section doesn't being inside a comment\n        var index = -1\n\n        // Go through the multiline comment ranges\n        var i = 0\n        val n = commentOffsets.size\n        while (i < n) {\n            val offsets = commentOffsets[i]\n\n            // If starting offset is past range, quit\n            if (offsets[0] > start + length) {\n                break\n            }\n            // Check to see if section begins inside a comment\n            if (offsets[0] <= start && offsets[1] >= start) {\n                // It does; determine if the closing comment marker is inside\n                // this section\n                index = if (offsets[1] > start + length) start + length\n                else offsets[1] + syntaxData!!.multiLineCommentEnd!!.length - 1\n            }\n            i++\n        }\n        return index\n    }\n\n    private fun isDefinedVariable(text: String): Boolean {\n        return StringUtil.isNotEmpty(text)\n    }\n\n    private fun atMultiLineCommentStart(text: String, position: Int): Boolean {\n        return text.indexOf(syntaxData!!.multiLineCommentStart!!, position) == position\n    }\n\n    private fun atStringStart(text: String, position: Int): Boolean {\n        return text.indexOf(syntaxData!!.stringStart!!, position) == position\n    }\n\n    private fun atVarnameReference(text: String, position: Int): Boolean {\n        return syntaxData!!.varnameReference != null && text.indexOf(syntaxData!!.varnameReference!!,\n                position) == position\n    }\n\n    private fun atSingleLineComment(text: String, position: Int): Boolean {\n        return syntaxData!!.comment != null && text.indexOf(syntaxData!!.comment!!, position) == position\n    }\n\n    private fun getKeywordEnd(lineText: String, start: Int): Int {\n\n        val length = lineText.length\n\n        val buf = StringBuilder(length)\n        var i = start\n\n        // Call any consecutive letters a word\n        while (i < length && Character.isLetter(lineText[i])) {\n            buf.append(lineText[i])\n            i++\n        }\n\n        return if (syntaxData!!.isKeyword(buf.toString())) i else 0 - i\n    }\n\n    /**\n     * Chop up the text into individual lines starting from offset and then\n     * determine the required styles for each. Ensures the offset is properly\n     * accounted for in each.\n\n     * @param text\n     * @param offset\n     * @param length\n     * @return\n     */\n    fun stylesFor(text: String, offset: Int, length: Int, lineSeparator: String): List<StyleRange> {\n\n        if (syntaxData == null) {\n            return emptyList()\n        }\n\n        val content = text.substring(offset, offset + length)\n        val lines = content.split(lineSeparator.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()\n\n        val styles = ArrayList<StyleRange>()\n\n        val separatorLength = lineSeparator.length\n\n        var currentOffset = offset\n\n        for (line in lines) {\n            val lineLength = line.length\n            val lineStyles = lineStylesFor(line, 0, lineLength)\n\n            for (sr in lineStyles) {\n                sr.start += currentOffset\n            }\n            styles.addAll(lineStyles)\n            currentOffset += lineLength + separatorLength\n        }\n\n        return styles\n    }\n\n    fun lineStylesFor(lineText: String, lineOffset: Int, length: Int): List<StyleRange> {\n\n        val styles = ArrayList<StyleRange>()\n\n        var start = 0\n\n        // Check if line begins inside a multiline comment\n        val mlIndex = getBeginsInsideComment(lineOffset, lineText.length)\n        if (mlIndex > -1) {\n            // Line begins inside multiline comment; create the range\n            styles.add(StyleRange(lineOffset, mlIndex - lineOffset, COMMENT_COLOR, COMMENT_BACKGROUND))\n            start = mlIndex\n        }\n        // Do punctuation, single-line comments, and keywords\n        while (start < length) {\n            // Check for multiline comments that begin inside this line\n            if (atMultiLineCommentStart(lineText, start)) {\n                // Determine where comment ends\n                var endComment = lineText.indexOf(syntaxData!!.multiLineCommentEnd!!, start)\n\n                // If comment doesn't end on this line, extend range to end of\n                // line\n                if (endComment == -1) {\n                    endComment = length\n                } else {\n                    endComment += syntaxData!!.multiLineCommentEnd!!.length\n                }\n                styles.add(StyleRange(lineOffset + start, endComment - start, COMMENT_COLOR, COMMENT_BACKGROUND))\n\n                start = endComment\n            } else if (atStringStart(lineText, start)) {\n                // Determine where comment ends\n                var endString = lineText.indexOf(syntaxData!!.stringEnd!!, start + 1)\n\n                // If string doesn't end on this line, extend range to end of\n                // line\n                if (endString == -1) {\n                    endString = length\n                } else {\n                    endString += syntaxData!!.stringEnd!!.length\n                }\n                styles.add(StyleRange(lineOffset + start, endString - start, STRING_COLOR, COMMENT_BACKGROUND))\n\n                start = endString\n            } else if (atSingleLineComment(lineText, start)) {\n                // line comments\n\n                styles.add(StyleRange(lineOffset + start, length - start, COMMENT_COLOR, COMMENT_BACKGROUND))\n                start = length\n            } else if (atVarnameReference(lineText, start)) {\n                // variable\n                // references\n\n                val buf = StringBuilder()\n                var i = start + syntaxData!!.varnameReference!!.length\n                // Call any consecutive letters a word\n                while (i < length && Character.isLetter(lineText[i])) {\n                    buf.append(lineText[i])\n                    i++\n                }\n\n                // See if the word is a variable\n                if (isDefinedVariable(buf.toString())) {\n                    // It's a keyword; create the StyleRange\n                    styles.add(StyleRange(lineOffset + start, i - start, REFERENCED_VAR_COLOR, null, SWT.BOLD))\n                }\n                // Move the marker to the last char (the one that wasn't a\n                // letter)\n                // so it can be retested in the next iteration through the loop\n                start = i\n            } else if (syntaxData!!.isPunctuation(lineText[start])) {\n                // Add range for punctuation\n                styles.add(StyleRange(lineOffset + start, 1, PUNCTUATION_COLOR, null))\n                ++start\n            } else if (Character.isLetter(lineText[start])) {\n\n                val kwEnd = getKeywordEnd(lineText, start)\n                // is a keyword\n\n                if (kwEnd > start) {\n                    styles.add(StyleRange(lineOffset + start, kwEnd - start, KEYWORD_COLOR, null))\n                }\n\n                // Move the marker to the last char (the one that wasn't a\n                // letter)\n                // so it can be retested in the next iteration through the loop\n                start = Math.abs(kwEnd)\n            } else {\n                ++start // It's nothing we're interested in; advance the marker\n            }// Check for punctuation\n        }\n\n        return styles\n    }\n\n    companion object {\n\n        private val COMMENT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN)\n        private val REFERENCED_VAR_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN)\n        private val UNREFERENCED_VAR_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW)\n        private val COMMENT_BACKGROUND = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)\n        private val PUNCTUATION_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)\n        private val KEYWORD_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_MAGENTA)\n        private val STRING_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/SyntaxData.kt",
    "content": "package com.alibaba.smartfox.eclipse.ui.pmd\n\n/**\n * This class contains information for syntax coloring and styling for an\n * extension\n */\nclass SyntaxData(val extension: String) {\n\n    var varnameReference: String? = null\n    var stringStart: String? = null\n    var stringEnd: String? = null\n    private var keywords: Collection<String>? = null\n    private var punctuation: String? = null\n    var comment: String? = null\n    var multiLineCommentStart: String? = null\n    var multiLineCommentEnd: String? = null\n\n    fun matches(otherExtension: String): Boolean {\n        return extension == otherExtension\n    }\n\n    fun isKeyword(word: String): Boolean {\n        return keywords != null && keywords!!.contains(word)\n    }\n\n    fun isPunctuation(ch: Char): Boolean {\n        return punctuation != null && punctuation!!.indexOf(ch) >= 0\n    }\n\n    fun setKeywords(keywords: Collection<String>) {\n        this.keywords = keywords\n    }\n\n    fun setPunctuation(thePunctuationChars: String) {\n        punctuation = thePunctuationChars\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/SyntaxManager.kt",
    "content": "package com.alibaba.smartfox.eclipse.ui.pmd\n\nimport org.eclipse.swt.custom.StyledText\nimport org.eclipse.swt.events.ModifyListener\nimport java.util.HashSet\nimport java.util.Hashtable\nimport java.util.MissingResourceException\nimport java.util.ResourceBundle\nimport java.util.StringTokenizer\n\n/**\n * This class manages the syntax coloring and styling data\n */\nobject SyntaxManager {\n\n    private val syntaxByExtension = Hashtable<String, SyntaxData>()\n\n    fun adapt(codeField: StyledText, languageCode: String, oldListener: ModifyListener?): ModifyListener? {\n\n        if (oldListener != null) {\n            codeField.removeModifyListener(oldListener)\n        }\n\n        val sd = SyntaxManager.getSyntaxData(languageCode) ?: return null\n\n        val blsl = BasicLineStyleListener(sd)\n        codeField.addLineStyleListener(blsl)\n\n        val ml = ModifyListener {\n            blsl.refreshMultilineComments(codeField.text)\n            codeField.redraw()\n        }\n        codeField.addModifyListener(ml)\n\n        return ml\n    }\n\n    /**\n     * Gets the syntax data for an extension\n     */\n    @Synchronized fun getSyntaxData(extension: String): SyntaxData? {\n        // Check in cache\n        var sd: SyntaxData? = syntaxByExtension[extension]\n        if (sd == null) {\n            // Not in cache; load it and put in cache\n            sd = loadSyntaxData(extension)\n            if (sd != null) {\n                syntaxByExtension.put(sd.extension, sd)\n            }\n        }\n        return sd\n    }\n\n    /**\n     * Loads the syntax data for an extension\n     * @return SyntaxData\n     */\n    private fun loadSyntaxData(filename: String): SyntaxData? {\n        var sd: SyntaxData? = null\n        try {\n            val rb = ResourceBundle.getBundle(\"/syntax/$filename\")\n            sd = SyntaxData(filename)\n\n            sd.stringStart = rb.getString(\"stringstart\")\n            sd.stringEnd = rb.getString(\"stringend\")\n            sd.multiLineCommentStart = rb.getString(\"multilinecommentstart\")\n            sd.multiLineCommentEnd = rb.getString(\"multilinecommentend\")\n\n            // Load the keywords\n            val keywords = HashSet<String>()\n            val st = StringTokenizer(rb.getString(\"keywords\"), \" \")\n            while (st.hasMoreTokens()) {\n                keywords.add(st.nextToken())\n            }\n            sd.setKeywords(keywords)\n\n            // Load the punctuation\n            sd.setPunctuation(rb.getString(\"punctuation\"))\n\n            if (rb.containsKey(\"comment\")) {\n                sd.comment = rb.getString(\"comment\")\n            }\n\n            if (rb.containsKey(\"varnamedelimiter\")) {\n                sd.varnameReference = rb.getString(\"varnamedelimiter\")\n            }\n\n        } catch (e: MissingResourceException) {\n            // Ignore\n        }\n\n        return sd\n    }\n}\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/util/CleanUps.kt",
    "content": "// =====================================================================\n//\n// Copyright (C) 2012 - 2016, Philip Graf\n//\n// All rights reserved. This program and the accompanying materials\n// are made available under the terms of the Eclipse Public License v1.0\n// which accompanies this distribution, and is available at\n// http://www.eclipse.org/legal/epl-v10.html\n//\n// =====================================================================\npackage com.alibaba.smartfox.eclipse.util\n\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport org.eclipse.core.filebuffers.FileBuffers\nimport org.eclipse.core.filebuffers.ITextFileBuffer\nimport org.eclipse.core.filebuffers.LocationKind\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.runtime.Assert\nimport org.eclipse.core.runtime.CoreException\nimport org.eclipse.core.runtime.IProgressMonitor\nimport org.eclipse.core.runtime.IStatus\nimport org.eclipse.core.runtime.NullProgressMonitor\nimport org.eclipse.core.runtime.Status\nimport org.eclipse.jdt.core.ICompilationUnit\nimport org.eclipse.jdt.core.IJavaProject\nimport org.eclipse.jdt.core.JavaCore\nimport org.eclipse.jdt.core.dom.CompilationUnit\nimport org.eclipse.jdt.internal.corext.fix.CleanUpConstants\nimport org.eclipse.jdt.internal.corext.fix.CleanUpRefactoring\nimport org.eclipse.jdt.internal.corext.fix.FixMessages\nimport org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser\nimport org.eclipse.jdt.internal.ui.JavaPlugin\nimport org.eclipse.jdt.internal.ui.actions.ActionUtil\nimport org.eclipse.jdt.internal.ui.fix.MapCleanUpOptions\nimport org.eclipse.jdt.ui.SharedASTProvider\nimport org.eclipse.jdt.ui.cleanup.CleanUpContext\nimport org.eclipse.jdt.ui.cleanup.CleanUpOptions\nimport org.eclipse.jdt.ui.cleanup.ICleanUp\nimport org.eclipse.jface.text.BadLocationException\nimport org.eclipse.jface.text.IDocument\nimport org.eclipse.jface.text.IDocumentExtension4\nimport org.eclipse.jface.window.Window\nimport org.eclipse.ltk.core.refactoring.Change\nimport org.eclipse.ltk.core.refactoring.CompositeChange\nimport org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes\nimport org.eclipse.ltk.core.refactoring.NullChange\nimport org.eclipse.ltk.core.refactoring.PerformChangeOperation\nimport org.eclipse.ltk.core.refactoring.RefactoringCore\nimport org.eclipse.ltk.core.refactoring.RefactoringStatus\nimport org.eclipse.ltk.core.refactoring.TextFileChange\nimport org.eclipse.ltk.ui.refactoring.RefactoringUI\nimport org.eclipse.text.edits.MalformedTreeException\nimport org.eclipse.text.edits.TextEdit\nimport org.eclipse.text.edits.UndoEdit\nimport org.eclipse.ui.PlatformUI\nimport java.util.ArrayList\nimport java.util.HashMap\nimport java.util.LinkedList\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/15\n */\nobject CleanUps {\n\n    private val WARNING_VALUE = \"warning\"\n    private val ERROR_VALUE = \"error\"\n\n    val cleanUpSettings = mapOf(CleanUpConstants.ADD_MISSING_ANNOTATIONS to CleanUpOptions.TRUE,\n            CleanUpConstants.CONTROL_STATMENTS_USE_BLOCKS_ALWAYS to CleanUpOptions.TRUE,\n            CleanUpConstants.ADD_MISSING_ANNOTATIONS_OVERRIDE to CleanUpOptions.TRUE,\n            CleanUpConstants.CONTROL_STATEMENTS_USE_BLOCKS to CleanUpOptions.TRUE,\n            CleanUpConstants.ADD_MISSING_ANNOTATIONS_OVERRIDE_FOR_INTERFACE_METHOD_IMPLEMENTATION to\n                    CleanUpOptions.TRUE)\n\n    fun fix(file: IFile, monitor: IProgressMonitor) {\n        val compilationUnit = JavaCore.createCompilationUnitFrom(file) ?: return\n        doCleanUp(compilationUnit, monitor)\n    }\n\n    @Throws(CoreException::class) fun doCleanUp(unit: ICompilationUnit, monitor: IProgressMonitor) {\n\n        monitor.beginTask(\"Fix\", IProgressMonitor.UNKNOWN)\n\n        if (!ActionUtil.isOnBuildPath(unit)) return\n        val result = CompositeChange(FixMessages.CleanUpPostSaveListener_SaveAction_ChangeName)\n        val undoEdits = LinkedList<UndoEdit>()\n        val oldFileValue = unit.resource.modificationStamp\n        val oldDocValue = getDocumentStamp(unit.resource as IFile, monitor)\n        val manager = RefactoringCore.getUndoManager()\n        var success = false\n\n        try {\n            manager.aboutToPerformChange(result)\n            success = doCleanUp(unit, monitor, result, undoEdits)\n        } finally {\n            manager.changePerformed(result, success)\n        }\n\n        if (undoEdits.size > 0) {\n            val undoEditArray = undoEdits.toTypedArray()\n            val undo = CleanUpSaveUndo(result.name, unit.resource as IFile, undoEditArray, oldDocValue, oldFileValue)\n            undo.initializeValidationData(NullProgressMonitor())\n            manager.addUndo(result.name, undo)\n        }\n    }\n\n    @Throws(CoreException::class) private fun getDocumentStamp(file: IFile, monitor: IProgressMonitor): Long {\n        val manager = FileBuffers.getTextFileBufferManager()\n        val path = file.fullPath\n\n        monitor.beginTask(\"\", 2)\n\n        var buffer: ITextFileBuffer? = null\n        try {\n            manager.connect(path, LocationKind.IFILE, monitor)\n            buffer = manager.getTextFileBuffer(path, LocationKind.IFILE)\n            val document = buffer!!.document\n\n            if (document is IDocumentExtension4) {\n                return document.modificationStamp\n            } else {\n                return file.modificationStamp\n            }\n        } finally {\n            if (buffer != null) manager.disconnect(path, LocationKind.IFILE, monitor)\n            monitor.done()\n        }\n    }\n\n    private fun doCleanUp(unit: ICompilationUnit, monitor: IProgressMonitor, result: CompositeChange,\n            undoEdits: LinkedList<UndoEdit>): Boolean {\n        val cleanUps = JavaPlugin.getDefault().cleanUpRegistry.createCleanUps(\n                setOf(\"org.eclipse.jdt.ui.cleanup.java50\", \"org.eclipse.jdt.ui.cleanup.control_statements\"))\n        val preCondition = RefactoringStatus()\n        val postCondition = RefactoringStatus()\n        cleanUps.forEach { cleanUp ->\n            cleanUp.setOptions(MapCleanUpOptions(cleanUpSettings))\n\n            preCondition.merge(cleanUp.checkPreConditions(unit.javaProject, arrayOf(unit), monitor))\n\n            val options = HashMap<String, String>(cleanUp.requirements.compilerOptions ?: emptyMap())\n\n            var ast = CleanUps.createAst(unit, options, monitor)\n            if (cleanUp.requirements.requiresAST()) {\n                ast = createAst(unit, options, monitor)\n            }\n\n            val context = CleanUpContext(unit, ast)\n\n            val undoneCleanUps = ArrayList<ICleanUp>()\n            val change = CleanUpRefactoring.calculateChange(context, arrayOf(cleanUp), undoneCleanUps, null)\n\n            postCondition.merge(cleanUp.checkPostConditions(monitor))\n            if (showStatus(postCondition) != Window.OK) {\n                return@doCleanUp false\n            }\n\n            if (change == null) {\n                return@forEach\n            }\n            result.add(change)\n\n            change.initializeValidationData(NullProgressMonitor())\n\n            val performChangeOperation = PerformChangeOperation(change)\n            performChangeOperation.setSchedulingRule(unit.schedulingRule)\n            performChangeOperation.run(monitor)\n            performChangeOperation.undoChange\n            undoEdits.addFirst(change.undoEdit)\n        }\n\n        return true\n    }\n\n    private fun showStatus(status: RefactoringStatus): Int {\n        if (!status.hasError()) return Window.OK\n\n        val shell = PlatformUI.getWorkbench().activeWorkbenchWindow.shell\n\n        val dialog = RefactoringUI.createRefactoringStatusDialog(status, shell, \"\", false)\n        return dialog.open()\n    }\n\n    private fun createAst(unit: ICompilationUnit, cleanUpOptions: Map<String, String>,\n            monitor: IProgressMonitor): CompilationUnit {\n        val project = unit.javaProject\n        if (compatibleOptions(project, cleanUpOptions)) {\n            val ast = SharedASTProvider.getAST(unit, SharedASTProvider.WAIT_NO, monitor)\n            if (ast != null) return ast\n        }\n\n        val parser = CleanUpRefactoring.createCleanUpASTParser()\n        parser.setSource(unit)\n\n        val compilerOptions = RefactoringASTParser.getCompilerOptions(unit.javaProject)\n        compilerOptions.putAll(cleanUpOptions)\n        parser.setCompilerOptions(compilerOptions)\n\n        return parser.createAST(monitor) as CompilationUnit\n    }\n\n    private fun compatibleOptions(project: IJavaProject, cleanUpOptions: Map<String, String>): Boolean {\n        if (cleanUpOptions.isEmpty()) {\n            return true\n        }\n\n        val projectOptions = project.getOptions(true)\n\n        return !cleanUpOptions.keys.any {\n            val projectOption = projectOptions[it]?.toString()\n            val cleanUpOption = cleanUpOptions[it]?.toString()\n            !strongerEquals(projectOption, cleanUpOption)\n        }\n    }\n\n    private fun strongerEquals(projectOption: String?, cleanUpOption: String?): Boolean {\n        if (projectOption == null) return false\n\n        if (ERROR_VALUE == cleanUpOption) {\n            return ERROR_VALUE == projectOption\n        } else if (WARNING_VALUE == cleanUpOption) {\n            return ERROR_VALUE == projectOption || WARNING_VALUE == projectOption\n        }\n\n        return false\n    }\n\n    private class CleanUpSaveUndo(name: String, private val fFile: IFile, private val fUndos: Array<UndoEdit>,\n            private val fDocumentStamp: Long, private val fFileStamp: Long) : TextFileChange(name,\n            fFile) {\n\n        init {\n            Assert.isNotNull(fUndos)\n        }\n\n        public override fun needsSaving(): Boolean {\n            return true\n        }\n\n        @Throws(CoreException::class) override fun perform(monitor: IProgressMonitor?): Change {\n            val pm = monitor ?: NullProgressMonitor()\n            if (isValid(pm).hasFatalError()) return NullChange()\n\n            val manager = FileBuffers.getTextFileBufferManager()\n            pm.beginTask(\"\", 2)\n            var buffer: ITextFileBuffer? = null\n\n            try {\n                manager.connect(fFile.fullPath, LocationKind.IFILE, pm)\n                buffer = manager.getTextFileBuffer(fFile.fullPath, LocationKind.IFILE)\n\n                val document = buffer!!.document\n                val oldFileValue = fFile.modificationStamp\n                val undoEditCollector = LinkedList<UndoEdit>()\n                val oldDocValue = LongArray(1)\n                val setContentStampSuccess = booleanArrayOf(false)\n\n                if (!buffer.isSynchronizationContextRequested) {\n                    performEdit(document, oldFileValue, undoEditCollector, oldDocValue, setContentStampSuccess)\n\n                } else {\n                    val fileBufferManager = FileBuffers.getTextFileBufferManager()\n\n                    class UIRunnable : Runnable {\n                        var fDone: Boolean = false\n                        var fException: Exception? = null\n\n                        override fun run() {\n                            synchronized(this) {\n                                try {\n                                    performEdit(document, oldFileValue, undoEditCollector, oldDocValue,\n                                            setContentStampSuccess)\n                                } catch (e: BadLocationException) {\n                                    fException = e\n                                } catch (e: MalformedTreeException) {\n                                    fException = e\n                                } catch (e: CoreException) {\n                                    fException = e\n                                } finally {\n                                    fDone = true\n                                    (this as Object).notifyAll()\n                                }\n                            }\n                        }\n                    }\n\n                    val runnable = UIRunnable()\n\n                    synchronized(runnable) {\n                        fileBufferManager.execute(runnable)\n                        while (!runnable.fDone) {\n                            try {\n                                (runnable as Object).wait(500)\n                            } catch (x: InterruptedException) {\n                            }\n\n                        }\n                    }\n\n                    if (runnable.fException != null) {\n                        if (runnable.fException is BadLocationException) {\n                            throw runnable.fException as BadLocationException\n                        } else if (runnable.fException is MalformedTreeException) {\n                            throw runnable.fException as MalformedTreeException\n                        } else if (runnable.fException is CoreException) {\n                            throw runnable.fException as CoreException\n                        }\n                    }\n                }\n\n                buffer.commit(pm, false)\n                if (!setContentStampSuccess[0]) {\n                    fFile.revertModificationStamp(fFileStamp)\n                }\n\n                return CleanUpSaveUndo(name, fFile, undoEditCollector.toTypedArray(), oldDocValue[0], oldFileValue)\n            } catch (e: BadLocationException) {\n                throw wrapBadLocationException(e)\n            } finally {\n                if (buffer != null) manager.disconnect(fFile.fullPath, LocationKind.IFILE, pm)\n            }\n        }\n\n        @Throws(MalformedTreeException::class, BadLocationException::class,\n                CoreException::class) private fun performEdit(document: IDocument, oldFileValue: Long,\n                editCollector: LinkedList<UndoEdit>,\n                oldDocValue: LongArray,\n                setContentStampSuccess: BooleanArray) {\n            if (document is IDocumentExtension4) {\n                oldDocValue[0] = document.modificationStamp\n            } else {\n                oldDocValue[0] = oldFileValue\n            }\n\n            // perform the changes\n            fUndos.map { it.apply(document, TextEdit.CREATE_UNDO) }.forEach { editCollector.addFirst(it) }\n\n            if (document is IDocumentExtension4 && fDocumentStamp != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) {\n                try {\n                    document.replace(0, 0, \"\", fDocumentStamp)\n                    setContentStampSuccess[0] = true\n                } catch (e: BadLocationException) {\n                    throw wrapBadLocationException(e)\n                }\n\n            }\n        }\n    }\n\n    private fun wrapBadLocationException(e: BadLocationException): CoreException {\n        var message: String? = e.message\n        if (message == null) message = \"BadLocationException\"\n        return CoreException(\n                Status(IStatus.ERROR, SmartfoxActivator.PLUGIN_ID, IRefactoringCoreStatusCodes.BAD_LOCATION, message,\n                        e))\n    }\n\n}"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/util/MarkerUtil.kt",
    "content": "// =====================================================================\n//\n// Copyright (C) 2012 - 2016, Philip Graf\n//\n// All rights reserved. This program and the accompanying materials\n// are made available under the terms of the Eclipse Public License v1.0\n// which accompanies this distribution, and is available at\n// http://www.eclipse.org/legal/epl-v10.html\n//\n// =====================================================================\npackage com.alibaba.smartfox.eclipse.util\n\nimport com.alibaba.smartfox.eclipse.QuickFixGenerator\nimport com.alibaba.smartfox.eclipse.SmartfoxActivator\nimport com.google.common.io.Files\nimport net.sourceforge.pmd.Rule\nimport net.sourceforge.pmd.RulePriority\nimport net.sourceforge.pmd.RuleViolation\nimport org.eclipse.core.resources.IFile\nimport org.eclipse.core.resources.IMarker\nimport org.eclipse.core.resources.IProject\nimport org.eclipse.core.resources.IResource\nimport org.eclipse.core.runtime.CoreException\nimport org.eclipse.jface.text.BadLocationException\nimport org.eclipse.jface.text.Document\nimport org.eclipse.ui.IMarkerResolution\nimport java.nio.charset.Charset\n\n/**\n * @author caikang\n * @date 2017/06/08\n */\nobject MarkerUtil {\n\n    private val PMD_TAB_SIZE = 8\n\n    private val MARKER_TYPE = \"${SmartfoxActivator.PLUGIN_ID}.p3cMarker\"\n\n    @Throws(CoreException::class)\n    fun removeAllMarkers(file: IFile) {\n        try {\n            if (file.exists()) {\n                file.deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_ZERO)\n            }\n        } catch (e: Exception) {\n            SmartfoxActivator.instance.logError(e.message ?: \"\", e)\n        }\n    }\n\n    @Throws(CoreException::class)\n    fun removeAllMarkers(project: IProject) {\n        project.deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_INFINITE)\n    }\n\n    @Throws(CoreException::class)\n    fun addMarker(file: IFile, violation: RuleViolation): IMarker {\n        val marker = file.createMarker(MARKER_TYPE)\n        marker.setAttribute(IMarker.MESSAGE, violation.description)\n        val severity = when (violation.rule.priority) {\n            RulePriority.HIGH -> IMarker.SEVERITY_ERROR\n            RulePriority.MEDIUM_HIGH -> IMarker.SEVERITY_WARNING\n            else -> IMarker.SEVERITY_INFO\n        }\n        marker.setRule(violation.rule.name)\n        marker.setAttribute(IMarker.SEVERITY, severity)\n        marker.setAttribute(IMarker.LINE_NUMBER, Math.max(violation.beginLine, 0))\n        val range = getAbsoluteRange(file, violation)\n        val start = Math.max(range.start, 0)\n        marker.setAttribute(IMarker.CHAR_START, start)\n        val end = Math.max(range.end, 0)\n        marker.setAttribute(IMarker.CHAR_END, end)\n        return marker\n    }\n\n\n    fun getAbsoluteRange(file: IFile, violation: RuleViolation): Range {\n        val content = Files.toString(file.rawLocation.toFile(), Charset.forName(file.charset))\n        try {\n            return calculateAbsoluteRange(content, violation)\n        } catch (e: BadLocationException) {\n            return Range(0, 0)\n        }\n    }\n\n    @Throws(BadLocationException::class) private fun calculateAbsoluteRange(content: String,\n            violation: RuleViolation): Range {\n        val document = Document(content)\n\n        // violation line and column start at one, the marker's start and end positions at zero\n        val start = getAbsolutePosition(content, document.getLineOffset(violation.beginLine - 1), violation.beginColumn)\n        val end = getAbsolutePosition(content, document.getLineOffset(violation.endLine - 1), violation.endColumn)\n\n        // for some rules PMD creates violations with the end position before the start position\n        val range = if (start <= end) {\n            Range(start - 1, end)\n        } else {\n            Range(end - 1, start)\n        }\n\n        return range\n    }\n\n    private fun getAbsolutePosition(content: String, lineOffset: Int, pmdCharOffset: Int): Int {\n        var pmdCharCounter = 0\n        var absoluteOffset = lineOffset\n        while (pmdCharCounter < pmdCharOffset) {\n            if (absoluteOffset < content.length) {\n                val c = content[absoluteOffset]\n                if (c == '\\t') {\n                    pmdCharCounter = (pmdCharCounter / PMD_TAB_SIZE + 1) * PMD_TAB_SIZE\n                } else {\n                    pmdCharCounter++\n                }\n            } else {\n                break\n            }\n            absoluteOffset++\n        }\n        return absoluteOffset\n    }\n}\n\nfun IMarker.setRule(rule: String) {\n    this.setAttribute(\"rule\", rule)\n}\n\nfun IMarker.getRule(): Rule {\n    return SmartfoxActivator.instance.getRule(this.getAttribute(\"rule\") as String)\n}\n\nfun IMarker.getResolution(): IMarkerResolution? {\n    return QuickFixGenerator.quickFixes[getRule().name]\n}\n\ndata class Range(val start: Int, val end: Int)\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/messages/P3cBundle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n<properties>\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler\">阿里编码规约扫描</entry>\n\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.text.cur_zh\">切换语言至英文(English)</entry>\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.text.cur_en\">切换语言至中文</entry>\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.success.en\">切换到English成功，是否重启</entry>\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.success.zh\">切换到中文成功，是否重启</entry>\n\n\n    <entry key=\"rule.standalone.MissingOverrideAnnotationRule.msg\"><![CDATA[所有的覆写方法，必须加@Override注解。]]></entry>\n    <entry key=\"rule.standalone.MissingOverrideAnnotationRule.desc\"><![CDATA[反例：getObject()与get0bject()的问题。一个是字母的O，一个是数字的0，加@Override可以准确判断是否覆盖成功。另外，如果在抽象类中对方法签名进行修改，其实现类会马上编译报错。]]></entry>\n    <entry key=\"rule.standalone.MissingOverrideAnnotationRule.error\"><![CDATA[方法缺少 '@Override' 注解]]></entry>\n    <entry key=\"rule.standalone.AvoidAccessStaticViaInstanceRule.msg\"><![CDATA[避免通过一个类的对象引用访问此类的静态变量或静态方法，无谓增加编译器解析成本，直接用类名来访问即可。]]></entry>\n    <entry key=\"rule.standalone.AvoidUseDeprecationRule.msg\"><![CDATA[不能使用过时的类或方法。]]></entry>\n    <entry key=\"rule.standalone.AvoidUseDeprecationRule.desc\"><![CDATA[说明：java.net.URLDecoder 中的方法decode(String encodeStr) 这个方法已经过时，应该使用双参数decode(String source, String encode)。接口提供方既然明确是过时接口，那么有义务同时提供新的接口；作为调用方来说，有义务去考证过时方法的新实现是什么。]]></entry>\n    <entry key=\"rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.msg\"><![CDATA[Map/Set的key为自定义对象时，必须重写hashCode和equals。]]></entry>\n    <entry key=\"rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.desc\"><![CDATA[关于hashCode和equals的处理，遵循如下规则：\n 1） 只要重写equals，就必须重写hashCode。\n 2） 因为Set存储的是不重复的对象，依据hashCode和equals进行判断，所以Set存储的对象必须重写这两个方法。\n 3） 如果自定义对象做为Map的键，那么必须重写hashCode和equals。]]></entry>\n</properties>"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/messages/P3cBundle_en.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n<properties>\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler\">Alibaba Coding Guidelines Analyze</entry>\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.text.cur_zh\">Switch language to English</entry>\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.text.cur_en\">Switch language to Chinese</entry>\n\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.success.en\">Switch language to English success，restart?</entry>\n    <entry key=\"com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.success.zh\">Switch language to Chinese success，restart?</entry>\n\n    <entry key=\"rule.standalone.MissingOverrideAnnotationRule.msg\"><![CDATA[An overridden method from an interface or abstract class must be marked with @Override annotation.]]></entry>\n    <entry key=\"rule.standalone.MissingOverrideAnnotationRule.desc\"><![CDATA[\n    Counter example: For getObject() and get0bject(), the first one has a letter 'O', and the second one has a number '0'. To accurately determine whether the overriding is successful, an @Override annotation is necessary. Meanwhile, once the method signature in the abstract class is changed, the implementation class will report a compile-time error immediately.]]></entry>\n    <entry key=\"rule.standalone.MissingOverrideAnnotationRule.error\"><![CDATA[Method missing '@Override' annotation]]></entry>\n    <entry key=\"rule.standalone.AvoidAccessStaticViaInstanceRule.msg\"><![CDATA[A static field or method should be directly referred by its class name instead of its corresponding object name.]]></entry>\n\n    <entry key=\"rule.standalone.AvoidUseDeprecationRule.msg\"><![CDATA[Using a deprecated class or method is prohibited.]]></entry>\n    <entry key=\"rule.standalone.AvoidUseDeprecationRule.desc\"><![CDATA[Note: For example, decode(String source, String encode) should be used instead of the deprecated method decode(String encodeStr). Once an interface has been deprecated, the interface provider has the obligation to provide a new one. At the same time, client programmers have the obligation to check out what its new implementation is.]]></entry>\n    <entry key=\"rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.msg\"><![CDATA[Custom class must override 'hashCode' and 'equals' while use as key for Map or value for Set.]]></entry>\n    <entry key=\"rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.desc\"><![CDATA[The usage of hashCode and equals should follow:\n 1) Override hashCode if equals is overridden.\n 2) These two methods must be overridden for Set since they are used to ensure that no duplicate object will be inserted in Set.\n 3) These two methods must be overridden if self-defined object is used as the key of Map.\nNote: String can be used as the key of Map since these two methods have been rewritten.]]></entry>\n</properties>"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/rulesets/java/ali-pmd.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"alibaba-pmd\"\n         xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <rule ref=\"rulesets/java/ali-concurrent.xml\"/>\n    <rule ref=\"rulesets/java/ali-comment.xml\"/>\n    <rule ref=\"rulesets/java/ali-naming.xml\"/>\n    <rule ref=\"rulesets/java/ali-constant.xml\"/>\n    <rule ref=\"rulesets/java/ali-other.xml\"/>\n    <rule ref=\"rulesets/java/ali-flowcontrol.xml\"/>\n    <rule ref=\"rulesets/java/ali-oop.xml\"/>\n    <rule ref=\"rulesets/java/ali-orm.xml\"/>\n    <rule ref=\"rulesets/java/ali-exception.xml\"/>\n    <rule ref=\"rulesets/java/ali-set.xml\"/>\n    <rule ref=\"rulesets/java/ali-ruleOnEclipse.xml\"/>\n</ruleset>\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/rulesets/java/ali-ruleOnEclipse.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"AlibabaRuleOnEclipse\"\n         xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n\n    <rule name=\"MissingOverrideAnnotationRule\" message=\"rule.standalone.MissingOverrideAnnotationRule.msg\"\n          class=\"com.alibaba.smartfox.eclipse.pmd.rule.MissingOverrideAnnotationRule\">\n        <description>rule.standalone.MissingOverrideAnnotationRule.desc</description>\n        <priority>1</priority>\n\n        <example>\n            <![CDATA[\n    /**\n     * @author caikang\n     * @date 2016/12/24\n     */\n    public class MissingOverrideAnnotationRule extends AbstractEclipseRule {\n        @Override\n        public Object visit(ASTCompilationUnit node, Object data) {\n            return super.visit(node, data);\n        }\n    }\n]]>\n        </example>\n    </rule>\n    <rule name=\"AvoidAccessStaticViaInstanceRule\" message=\"rule.standalone.AvoidAccessStaticViaInstanceRule.msg\"\n          class=\"com.alibaba.smartfox.eclipse.pmd.rule.AvoidAccessStaticViaInstanceRule\">\n        <priority>1</priority>\n    </rule>\n    <rule name=\"AvoidUseDeprecationRule\" message=\"rule.standalone.AvoidUseDeprecationRule.msg\"\n          class=\"com.alibaba.smartfox.eclipse.pmd.rule.AvoidUseDeprecationRule\">\n        <description>rule.standalone.AvoidUseDeprecationRule.desc</description>\n        <priority>2</priority>\n    </rule>\n\n    <rule name=\"MapOrSetKeyShouldOverrideHashCodeEqualsRule\" message=\"rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.msg\"\n          class=\"com.alibaba.smartfox.eclipse.pmd.rule.MapOrSetKeyShouldOverrideHashCodeEqualsRule\">\n        <description>rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.desc</description>\n        <priority>2</priority>\n    </rule>\n</ruleset>\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/syntax/java.properties",
    "content": "# This file contains the syntax data for .java files\ncomment=//\nstringstart=\"\nstringend=\"\nmultilinecommentstart=/*\nmultilinecommentend=*/\npunctuation=(){};:?<>=+-*/&|~!%.[]\nkeywords=abstract assert boolean break byte case catch char class const continue do double else enum extends false final finally for if implements import int interface native new null package protected public private return static strictfp super switch synchronized this throws true try void volatile while\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.updatesite/category.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<site>\n   <description url=\"https://p3c.alibaba.com/plugin/eclipse/update\">\n      Alibaba Java Coding Guidelines\n   </description>\n   <feature id=\"com.alibaba.smartfox.eclipse.feature\" version=\"0.0.0\">\n      <category name=\"Smartfox\"/>\n   </feature>\n   <category-def name=\"Smartfox\" label=\"Smartfox Eclipse Plugin\"/>\n</site>\n"
  },
  {
    "path": "eclipse-plugin/com.alibaba.smartfox.eclipse.updatesite/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>com.alibaba.smartfox.eclipse</groupId>\n    <artifactId>smartfox-eclipse</artifactId>\n    <version>2.0.1-SNAPSHOT</version>\n  </parent>\n  <artifactId>com.alibaba.smartfox.eclipse.updatesite</artifactId>\n  <packaging>eclipse-repository</packaging>\n  <inceptionYear>2017</inceptionYear>\n</project>\n"
  },
  {
    "path": "eclipse-plugin/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.alibaba.smartfox.eclipse</groupId>\n    <artifactId>smartfox-eclipse</artifactId>\n    <version>2.0.1-SNAPSHOT</version>\n    <packaging>pom</packaging>\n    <inceptionYear>2017</inceptionYear>\n    <properties>\n        <tycho.version>1.0.0</tycho.version>\n        <tycho-extras.version>${tycho.version}</tycho-extras.version>\n        <eclipse-repo.url>http://download.eclipse.org/releases/neon</eclipse-repo.url>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <ajdt-eclipse-repo.url>http://download.eclipse.org/tools/ajdt/46/dev/update</ajdt-eclipse-repo.url>\n        <kotlin.version>1.3.30</kotlin.version>\n        <eclipse-release>juno</eclipse-release>\n    </properties>\n    <modules>\n        <module>com.alibaba.smartfox.eclipse.plugin</module>\n        <module>com.alibaba.smartfox.eclipse.feature</module>\n        <module>com.alibaba.smartfox.eclipse.updatesite</module>\n    </modules>\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.11</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.jetbrains.kotlin</groupId>\n                <artifactId>kotlin-stdlib-jdk8</artifactId>\n                <version>${kotlin.version}</version>\n                <scope>compile</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <repositories>\n        <repository>\n            <id>juno</id>\n            <layout>p2</layout>\n            <url>http://mirrors.ustc.edu.cn/eclipse/releases/juno/</url>\n        </repository>\n        <repository>\n            <id>sonatype-nexus-snapshots</id>\n            <name>Sonatype Nexus Snapshots</name>\n            <url>https://oss.sonatype.org/content/repositories/snapshots</url>\n            <releases>\n                <enabled>false</enabled>\n            </releases>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-maven-plugin</artifactId>\n                <version>${tycho.version}</version>\n                <extensions>true</extensions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n                <configuration>\n                    <environments>\n                        <environment>\n                            <os>linux</os>\n                            <ws>gtk</ws>\n                            <arch>x86</arch>\n                        </environment>\n                        <environment>\n                            <os>linux</os>\n                            <ws>gtk</ws>\n                            <arch>x86_64</arch>\n                        </environment>\n                        <environment>\n                            <os>win32</os>\n                            <ws>win32</ws>\n                            <arch>x86</arch>\n                        </environment>\n                        <environment>\n                            <os>win32</os>\n                            <ws>win32</ws>\n                            <arch>x86_64</arch>\n                        </environment>\n                        <environment>\n                            <os>macosx</os>\n                            <ws>cocoa</ws>\n                            <arch>x86_64</arch>\n                        </environment>\n                    </environments>\n                </configuration>\n            </plugin>\n        </plugins>\n\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>target-platform-configuration</artifactId>\n                    <version>${tycho.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-compiler-plugin</artifactId>\n                    <version>${tycho.version}</version>\n                    <configuration>\n                        <compilerVersion>1.8</compilerVersion>\n                        <compilerArguments>\n                            <inlineJSR/>\n                            <enableJavadoc/>\n                            <encoding>UTF-8</encoding>\n                        </compilerArguments>\n                        <compilerArgument>-err:-forbidden</compilerArgument>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.codehaus.mojo</groupId>\n                    <artifactId>aspectj-maven-plugin</artifactId>\n                    <version>${aspectj.plugin.version}</version>\n                    <dependencies>\n                        <dependency>\n                            <groupId>org.aspectj</groupId>\n                            <artifactId>aspectjtools</artifactId>\n                            <version>${aspectj.version}</version>\n                        </dependency>\n                    </dependencies>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-packaging-plugin</artifactId>\n                    <version>${tycho.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-surefire-plugin</artifactId>\n                    <version>${tycho.version}</version>\n                    <configuration>\n                        <testFailureIgnore>true</testFailureIgnore>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-source-plugin</artifactId>\n                    <version>${tycho.version}</version>\n                    <configuration>\n                        <strictSrcIncludes>false</strictSrcIncludes>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-p2-director-plugin</artifactId>\n                    <version>${tycho.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-p2-repository-plugin</artifactId>\n                    <version>${tycho.version}</version>\n                    <configuration>\n                        <finalName>smartfox-eclipse-plugin</finalName>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho.extras</groupId>\n                    <artifactId>tycho-source-feature-plugin</artifactId>\n                    <version>${tycho-extras.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho.extras</groupId>\n                    <artifactId>tycho-custom-bundle-plugin</artifactId>\n                    <version>${tycho-extras.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-p2-plugin</artifactId>\n                    <version>${tycho.version}</version>\n                    <configuration>\n                        <baselineMode>warn</baselineMode>\n                        <baselineReplace>none</baselineReplace>\n                        <baselineRepositories>\n                            <repository>\n                                <url>http://download.eclipse.org/eclipse/updates/4.4</url>\n                            </repository>\n                        </baselineRepositories>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "idea-plugin/.gitignore",
    "content": "# Gradle\nbuild\n.gradle\n\ntestdata/\n# Java gitignore #\n.class\n.log\n\n# Package Files #\n\n*.war\n*.ear\n\n#hsf files\nconfiguration\n\n# maven gitignore#\ntarget/**\n\n.svn/\n\n# intelliJ.gitignore #\n.idea\n*.iml\n*.ipr\n*.iws\n\n# Eclipse git ignore#\n*.pydevproject\n.project\n.metadata\nbin/**\n*/bin/**\ntmp/**\ntmp/**/*\nconfiguration/**\n*.tmp\n*.bak\n*.orig\n*.swp\n*~.nib\n.classpath\n.settings/\n.loadpath\n.fileTable*\n.cache\n\n# External tool builders\n.externalToolBuilders/\n\n# Locally stored \"Eclipse launch configurations\"\n*.launch\n\n# CDT-specific\n.cproject\n\n# PDT-specific\n.buildpath\n\n#log\n*.log\n*.log.*\n\n# Windows Thumbs.db\n*.db\n\n# OSX\n.DS_Store\n\n# sass gitignore#\n.sass-cache\n.idea\n\n# tcc_coverage\ncoverage.ec\n\n\n\nconfig.client.*\n\ntemp/\n*.pid\n*.orig\n\nhsf.configuration/\n\n# code coverage report\n*.ec\n\n#hsf test\n*.instance\nout\n**/idea-sandbox"
  },
  {
    "path": "idea-plugin/README.md",
    "content": "# Idea Plugin \n---\n## <font color=\"green\">Prepare</font>\n- Project JDK: 1.7+\n- Gradle: 3.0+（Require JDK1.8+ for gradle）\n\n## <font color=\"green\">Build</font>\n```\ncd p3c-idea\n../gradlew clean buildPlugin\n```\n\n## <font color=\"green\">Run plugin</font>\n\n```\ncd p3c-idea\n../gradlew runIde\n# run specific IDEA\n../gradlew runIde -Pidea_version=2018.3\n```\n\n## <font color=\"green\">Use p3c-common as your plugin dependency</font>\n```groovy\ncompile 'com.alibaba.p3c.idea:p3c-common:1.0.0'\n```\n## [中文使用手册](README_cn.md)\n## <font color=\"green\">Install</font>\n### Install from repositories\n1. <font color=\"blue\">Settings >> Plugins >> Browse repositories... </font>\n\n    ![Switch language](doc/images/install_1.png) \n\n2. <font color=\"blue\"> Search plugin by keyword 'alibaba' then install 'Alibaba Java Coding Guidelines' plugin </font>\n\n    ![Switch language](doc/images/install_2.png) \n\n3.  <font color=\"blue\">Restart to take effect. </font>\n### Install from local zip file.\n1. Open https://plugins.jetbrains.com/plugin/10046-alibaba-java-coding-guidelines and download the latest version zip file.\n    ![download](https://gw.alicdn.com/tfscom/TB1WcF3hzlxYKJjSZFuXXaYlVXa.png)\n2. Settings >> Plugins >> Install plugin from disk...,select the downloaded zip file in previous step then restart your idea\n    ![](https://gw.alicdn.com/tfscom/TB1WFsKiqigSKJjSsppXXabnpXa.png)\n\n## <font color=\"green\">Use</font>\n\n1. <font color=\"blue\">Switch language</font>\n\n\t![Switch language](doc/images/switch_language.png) \n\n2. <font color=\"blue\">Inspections</font>  \n\n\t![Real time](doc/images/inspection.png) \n\t\n\t![Settings](doc/images/inspection_setting.png)  \n\n3. <font color=\"blue\">Code Analyze</font>  \n\n\t![Settings](doc/images/analyze.png)  \n\t\n\t<font color=\"blue\">We use the idea standard Inspection Results to show our violations.</font>  \n\t \n\t![Result](doc/images/inspection_result.png)  \n\t\n\t<font color=\"blue\">We can also analyze file which is modified before vcs checkin.</font>  \n\t\n\t![Before Checkin](doc/images/analyze_before_checkin.png) \n\n## <font color=\"green\">Other</font>\n1. <font color=\"blue\">[中文乱码解决方法](https://github.com/alibaba/p3c/issues/32#issuecomment-336762512)</font>\n\n\t* <font color=\"blue\">Appearance&Behavior -> Appearance -> UI Options -> Name 里面设置成微软雅黑（microsoft yahei light）</font>\n\n\t   ![Font](doc/images/change_name.png) \n \n\t* <font color=\"blue\">Switch Language to English and restart.</font>\n\n\t   ![Switch language](doc/images/normal_view.png) \n\n"
  },
  {
    "path": "idea-plugin/README_cn.md",
    "content": "> 首先非常感谢大家对插件的支持与意见，英文版的文档还是略为简单，这里详细介绍一下插件的安装使用。\n\n## 插件安装\n### 通过Jetbrains官方仓库安装\n1. 打开 Settings >> Plugins >> Browse repositories...\n\n ![](https://gw.alicdn.com/tfscom/TB1Qn83ifBNTKJjy1zdXXaScpXa.png)\n \n2. 在搜索框输入alibaba即可看到Alibaba Java Code Guidelines插件，点击Install进行安装，然后重启IDE生效 `注意：因为插件zip包托管在Jetbrains官方CDN上，所以是从国外的服务器进行下载，可能会出现超时的情况`\n\n   ![](https://gw.alicdn.com/tfscom/TB1vcGbmYsTMeJjy1zcXXXAgXXa.png)\n\n### 通过下载安装包进行安装\n1. 打开[插件](https://plugins.jetbrains.com/plugin/10046-alibaba-java-coding-guidelines)页面\n\n![download](https://gw.alicdn.com/tfscom/TB1WcF3hzlxYKJjSZFuXXaYlVXa.png)\n\n2. Settings >> Plugins >> Install plugin from disk...，选择刚刚下载的zip包安装，然后重启IDE\n\n ![](https://gw.alicdn.com/tfscom/TB1WFsKiqigSKJjSsppXXabnpXa.png)\n\n\n### 注意\n\n最低支持IDEA版本为14.1（buildNumber 141.0，可以在About Intellij IDEA中查看版本信息），使用IDEA14的同学最好升级到14.1.7(<a href=\"https://www.jetbrains.com/idea/download/previous.html\" target=\"_blank\">历史版本传送门</a>)\n\n插件基于JDK1.7打包，所以IDEA启动时使用的JDK版本如果是1.6的话就会报Unsupported major.minor version 51.0异常，建议大家都升级一下。\n\n### [中文乱码解决方法](https://github.com/alibaba/p3c/issues/32#issuecomment-336762512)\n\n1. 修改字体——Appearance&Behavior -> Appearance -> UI Options -> Name 里面设置成中文字体——如微软雅黑（microsoft yahei light）、文泉驿(linux)\n\n\t![](https://gw.alicdn.com/tfscom/TB14wTmm3oQMeJjy0FoXXcShVXa.png) \n\n2. Switch Language to English and restart.\n\n\t![](https://gw.alicdn.com/tfscom/TB1Z6u1mYsTMeJjSszhXXcGCFXa.png) \n\t   \n\n## 插件使用\n\n目前插件实现了开发手册中的的53条规则，大部分基于PMD实现，其中有4条规则基于IDEA实现，并且基于IDEA <a href=\"https://www.jetbrains.com/help/idea/code-inspection.html\" target=\"_blank\">Inspection</a>实现了实时检测功能。部分规则实现了Quick Fix功能，对于可以提供Quick Fix但没有提供的，我们会尽快实现，也欢迎有兴趣的同学加入进来一起努力。\n目前插件检测有两种模式：实时检测、手动触发。\n\n### 实时检测\n实时检测功能会在开发过程中对当前文件进行检测，并以高亮的形式提示出来，同时也可以支持Quick Fix，该功能默认开启，可以通过配置关闭。 \n\n#### 结果高亮提示\n\n<p style=\"text-indent:2em\">检测结果高亮提示，并且鼠标放上去会弹出提示信息。</p>\n\n  ![](https://gw.alicdn.com/tfscom/TB17wt3mYsTMeJjSszdXXcEupXa.png)\n\n  ![](https://gw.alicdn.com/tfscom/TB1Rq85ifNNTKJjSspkXXaeWFXa.png)\n\n#### <a href=\"https://www.jetbrains.com/help/idea/intention-actions.html\" target=\"_blank\">Intention</a> QuickFix功能\n\nAlt+Enter键可呼出Intention菜单，不同的规则会提示不同信息的Quick Fix按钮\n\n  ![](https://gw.alicdn.com/tfscom/TB1twLMsOAKL1JjSZFoXXagCFXa.png)\n\n#### 关闭实时检测  \n在某些情况下，我们不希望对代码提示违规信息，比如我们在阅读Github开源项目代码的时候，如果界面出现一堆红色、黄色的提示，此时心里肯定是飘过一万只草泥马。这个时候我们可以通过Inspection的设置关闭实时检测功能。\n1. 通过右键快速关闭（打开）所有规则的实时检测功能\n\n  ![](https://gw.alicdn.com/tfscom/TB1dBbDe_1z01JjSZFCXXXY.XXa.png)\n2. 通过Settings >> Editor >> Inspections 进行手动设置  \n\n ![](https://gw.alicdn.com/tfscom/TB1zhCBsiFTMKJjSZFAXXckJpXa.png)\n\n也可以关闭某条规则的实时检测功能或者修改提示级别。\n   \n### 代码扫描\n\n可以通过右键菜单、Toolbar按钮、快捷键三种方式手动触发代码检测。同时结果面板中可以对部分实现了QuickFix功能的规则进行快速修复。 \n\n#### 触发扫描\n在当前编辑的文件中点击右键，可以在弹出的菜单中触发对该文件的检测。\n\n   ![](https://gw.alicdn.com/tfscom/TB1Wj49mYsTMeJjSszdXXcEupXa.png)\n   \n在左侧的Project目录树种点击右键，可以触发对整个工程或者选择的某个目录、文件进行检测。\n\n   ![](https://gw.alicdn.com/tfscom/TB1h_XciWmgSKJjSspiXXXyJFXa.png)\n   \n   如果您打开了IDE的Toolbar，也可以通过Toolbar中的按钮来触发检测，目前Toolbar的按钮触发的检测范围与您IDE当时的焦点有关，如当前编辑的文件或者是Project目录树选中的项，是不是感觉与右键菜单的检测范围类似呢。\n\n   ![](https://gw.alicdn.com/tfscom/TB1q3Nfi6uhSKJjSspmXXcQDpXa.png)\n   使用快捷键（Ctrl+Shift+Alt+J）触发弹出窗口，选择检测范围；您也可自定义快捷键。\n\n   ![](https://gw.alicdn.com/tfscom/TB1k4uXmYwTMeJjSszfXXXbtFXa.png) \n   \n   ![](https://gw.alicdn.com/tfscom/TB1ObqXifxNTKJjy0FjXXX6yVXa.png)\n   \n#### 扫描结果  \n检测结果直接使用IDEA Run Inspection By Name功能的结果界面，插件的检测结果分级为Blocker、Critical、Major。默认按等级分组，方便统计每个级别错误的数量。\n\n![](https://gw.alicdn.com/tfscom/TB1aC1yifJNTKJjSspoXXc6mpXa.png)\n\n   \n默认情况我们在结果面板需要双击具体违规项才能打开对应的源文件，开启Autoscroll To Source选项，单击面板中的文件名、或者是具体的违规项的时候IDEA会自动打开对应的源文件。\n\n   ![](https://gw.alicdn.com/tfscom/TB1aIixmYsTMeJjy1zcXXXAgXXa.png)\n \n#### QuickFix\n对于实现Quick Fix的规则，在结果面板中可以直接一键修复 `注意：IDEA14、15可以通过左下角的灯泡进行一键修复操作。`\n\n   ![](https://gw.alicdn.com/tfscom/TB1Kw5Vm3oQMeJjy0FpXXcTxpXa.png)\n   \n   ![](https://gw.alicdn.com/tfscom/TB1lHZZiGagSKJjy0FbXXa.mVXa.png)\n   \n#### 其他\n面板中其他按钮的功能大家自行探索吧，就不一一赘述了\n\n### 代码提交时检测\n1. 在提交代码框勾选Alibaba Code Guidelines选项\n   ![](https://gw.alicdn.com/tfscom/TB1u_ZZjamgSKJjSspiXXXyJFXa.png)\n2. 如果有违反手册的地方会提示是否继续提交，选择取消后会自动对修改的代码进行扫描\n   ![](https://gw.alicdn.com/tfscom/TB1r5PUXbb85uJjSZFmXXcgsFXa.png)\n"
  },
  {
    "path": "idea-plugin/build.gradle",
    "content": "buildscript {\n    repositories {\n        maven {\n            url \"https://oss.sonatype.org/content/repositories/snapshots/\"\n        }\n        maven {\n            url 'http://dl.bintray.com/jetbrains/intellij-plugin-service'\n        }\n        mavenCentral()\n\n    }\n    dependencies {\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    group 'com.alibaba.p3c.idea'\n    apply plugin: 'java'\n    apply plugin: 'kotlin'\n    apply plugin: 'maven-publish'\n\n    sourceCompatibility = 1.8\n    compileJava.options.encoding = 'UTF-8'\n    configurations.all {\n        resolutionStrategy.cacheChangingModulesFor 0, 'seconds'\n    }\n    repositories {\n        jcenter()\n        mavenCentral()\n    }\n\n    dependencies {\n        compile \"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version\"\n        testCompile group: 'junit', name: 'junit', version: '4.11'\n    }\n}\n\n"
  },
  {
    "path": "idea-plugin/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.6-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "idea-plugin/gradle.properties",
    "content": "kotlin_version=1.3.72\nidea_version=2018.3\nplugin_name=Alibaba Java Coding Guidelines\ngradle_jetbrains_version=0.4.5\nsystemProp.file.encoding=UTF-8\n\nplugin_version=2.1.0\n"
  },
  {
    "path": "idea-plugin/gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    \n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "idea-plugin/gradlew.bat",
    "content": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\n@rem you may not use this file except in compliance with the License.\n@rem You may obtain a copy of the License at\n@rem\n@rem      https://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "idea-plugin/p3c-common/build.gradle",
    "content": "plugins {\n    id \"org.jetbrains.intellij\" version '0.4.5'\n}\napply plugin: 'kotlin'\napply plugin: 'idea'\napply plugin: 'maven'\napply plugin: 'signing'\n\njavadoc {\n    options.tags = [\"date\"]\n}\n\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from 'build/docs/javadoc'\n}\n\ntask sourcesJar(type: Jar) {\n    classifier = 'sources'\n    from sourceSets.main.allSource\n}\n\nartifacts {\n    archives jar\n    archives javadocJar\n    archives sourcesJar\n}\n\ndef myPlugins = []\ndef versionDotIndex = idea_version.indexOf('.')\ndef intVersion = versionDotIndex == -1 ? Integer.parseInt(idea_version) : Integer.parseInt(idea_version.substring(0, versionDotIndex))\nif (intVersion >= 2019 || (intVersion < 1000 && intVersion >= 193)) {\n    myPlugins = ['java']\n}\n\nintellij {\n    version idea_version\n    plugins = myPlugins\n    pluginName plugin_name\n    updateSinceUntilBuild false\n    sandboxDirectory \"$project.buildDir/idea-sandbox/$idea_version\"\n}\nversion '2.0.1'\n\next.isReleaseVersion = !version.endsWith(\"SNAPSHOT\")\n\ndependencies {\n    compile group: 'org.freemarker', name: 'freemarker', version: '2.3.25-incubating'\n    compile 'com.alibaba.p3c:p3c-pmd:2.1.0'\n    compile group: 'org.javassist', name: 'javassist', version: '3.21.0-GA'\n}\n\nuploadArchives {\n    repositories {\n        mavenDeployer {\n            beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }\n\n            repository(url: \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\") {\n                authentication(userName: findProperty('ossrhUsername'), password: findProperty('ossrhPassword'))\n            }\n\n            snapshotRepository(url: \"https://oss.sonatype.org/content/repositories/snapshots/\") {\n                authentication(userName: findProperty('ossrhUsername'), password: findProperty('ossrhPassword'))\n            }\n\n            pom.project {\n                name 'p3c-common'\n                packaging 'jar'\n                description 'P3c Idea Plugin Common.'\n                url 'https://github.com/alibaba/p3c'\n\n                scm {\n                    url 'https://github.com/alibaba/p3c'\n                    connection 'scm:git:https://git@github.com/alibaba/p3c.git'\n                }\n\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                        distribution 'repo'\n                    }\n                }\n\n                developers {\n                    developer {\n                        id 'junlie'\n                        name 'Junlie'\n                        email 'sean.caikang@gmail.com'\n                    }\n                    developer {\n                        id 'ZengHou'\n                        name 'ZengHou'\n                        email 'fengwei1983@gmail.com'\n                    }\n                }\n            }\n        }\n    }\n}\n\nsigning {\n    required {\n        isReleaseVersion && gradle.taskGraph.hasTask(\"uploadArchives\")\n    }\n    sign configurations.archives\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/java/icons/P3cIcons.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage icons;\n\nimport javax.swing.Icon;\n\nimport com.intellij.openapi.util.IconLoader;\n\n/**\n * @author caikang\n * @date 2016/12/28\n */\npublic final class P3cIcons {\n    private P3cIcons() {\n        throw new AssertionError(\"icons.P3cIcons\"\n            + \" instances for you!\");\n    }\n\n    public static final Icon ANALYSIS_ACTION = IconLoader.getIcon(\"/icons/ali-ide-run.png\");\n\n    public static final Icon PROJECT_INSPECTION_ON = IconLoader.getIcon(\"/icons/qiyong.png\");\n    public static final Icon PROJECT_INSPECTION_OFF = IconLoader.getIcon(\"/icons/tingyong.png\");\n    public static final Icon LANGUAGE = IconLoader.getIcon(\"/icons/language.png\");\n    public static final Icon ALIBABA = IconLoader.getIcon(\"/icons/alibaba.png\");\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/AliInspectionAction.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.action\n\nimport com.alibaba.p3c.idea.compatible.inspection.InspectionProfileService\nimport com.alibaba.p3c.idea.compatible.inspection.Inspections\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.inspection.AliBaseInspection\nimport com.alibaba.p3c.idea.util.NumberConstants\nimport com.google.common.collect.Lists\nimport com.intellij.analysis.AnalysisScope\nimport com.intellij.analysis.AnalysisUIOptions\nimport com.intellij.analysis.BaseAnalysisActionDialog\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.InspectionsBundle\nimport com.intellij.codeInspection.ex.GlobalInspectionContextImpl\nimport com.intellij.codeInspection.ex.InspectionManagerEx\nimport com.intellij.codeInspection.ex.InspectionToolWrapper\nimport com.intellij.openapi.actionSystem.AnAction\nimport com.intellij.openapi.actionSystem.AnActionEvent\nimport com.intellij.openapi.actionSystem.CommonDataKeys\nimport com.intellij.openapi.components.ServiceManager\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.openapi.module.Module\nimport com.intellij.openapi.module.ModuleUtilCore\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.vfs.VfsUtilCore\nimport com.intellij.openapi.vfs.VirtualFile\nimport com.intellij.openapi.wm.ToolWindowId\nimport com.intellij.openapi.wm.ToolWindowManager\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiFile\nimport com.intellij.psi.PsiFileSystemItem\nimport com.intellij.psi.PsiManager\nimport java.awt.event.KeyEvent\n\n/**\n * @author caikang\n * @date 2016/12/11\n */\nclass AliInspectionAction : AnAction() {\n\n    override fun actionPerformed(e: AnActionEvent) {\n        val project = e.project ?: return\n        val analysisUIOptions = ServiceManager.getService(project, AnalysisUIOptions::class.java)!!\n        analysisUIOptions.GROUP_BY_SEVERITY = true\n\n        val managerEx = InspectionManager.getInstance(project) as InspectionManagerEx\n        val toolWrappers = Inspections.aliInspections(project) {\n            it.tool is AliBaseInspection\n        }\n        val psiElement = e.getData<PsiElement>(CommonDataKeys.PSI_ELEMENT)\n        val psiFile = e.getData<PsiFile>(CommonDataKeys.PSI_FILE)\n        val virtualFile = e.getData<VirtualFile>(CommonDataKeys.VIRTUAL_FILE)\n        val virtualFiles = e.getData<Array<VirtualFile>>(CommonDataKeys.VIRTUAL_FILE_ARRAY)\n        var analysisScope: AnalysisScope? = null\n        var projectDir = false\n        if (psiFile != null) {\n            analysisScope = AnalysisScope(psiFile)\n            projectDir = isBaseDir(psiFile.virtualFile, project)\n        } else if (virtualFiles != null && virtualFiles.size > NumberConstants.INTEGER_SIZE_OR_LENGTH_0) {\n            analysisScope = AnalysisScope(project, Lists.newArrayList<VirtualFile>(*virtualFiles))\n            projectDir = virtualFiles.any {\n                isBaseDir(it, project)\n            }\n        } else {\n            if (virtualFile != null && virtualFile.isDirectory) {\n                val psiDirectory = PsiManager.getInstance(project).findDirectory(virtualFile)\n                if (psiDirectory != null) {\n                    analysisScope = AnalysisScope(psiDirectory)\n                    projectDir = isBaseDir(virtualFile, project)\n                }\n            }\n            if (analysisScope == null && virtualFile != null) {\n                analysisScope = AnalysisScope(project, listOf(virtualFile))\n                projectDir = isBaseDir(virtualFile, project)\n            }\n            if (analysisScope == null) {\n                projectDir = true\n                analysisScope = AnalysisScope(project)\n            }\n        }\n        if (e.inputEvent is KeyEvent) {\n            inspectForKeyEvent(project, managerEx, toolWrappers, psiElement, psiFile, virtualFile, analysisScope)\n            return\n        }\n        val element = psiFile ?: psiElement\n        analysisScope.isIncludeTestSource = false\n        analysisScope.setSearchInLibraries(true)\n        createContext(\n            toolWrappers, managerEx, element,\n            projectDir, analysisScope\n        ).doInspections(analysisScope)\n    }\n\n    private fun isBaseDir(file: VirtualFile, project: Project): Boolean {\n        if (file.canonicalPath == null || project.basePath == null) {\n            return false\n        }\n        return project.basePath == file.canonicalPath\n    }\n\n    private fun inspectForKeyEvent(\n        project: Project, managerEx: InspectionManagerEx,\n        toolWrappers: List<InspectionToolWrapper<*, *>>, psiElement: PsiElement?, psiFile: PsiFile?,\n        virtualFile: VirtualFile?, analysisScope: AnalysisScope\n    ) {\n        var module: Module? = null\n        if (virtualFile != null && project.baseDir != virtualFile) {\n            module = ModuleUtilCore.findModuleForFile(virtualFile, project)\n        }\n\n        val uiOptions = AnalysisUIOptions.getInstance(project)\n        uiOptions.ANALYZE_TEST_SOURCES = false\n        val dialog = BaseAnalysisActionDialog(\n            \"Select Analyze Scope\", \"Analyze Scope\", project, analysisScope,\n            module?.name, true, uiOptions, psiElement\n        )\n\n        if (!dialog.showAndGet()) {\n            return\n        }\n        val scope = dialog.getScope(uiOptions, analysisScope, project, module)\n        scope.setSearchInLibraries(true)\n        val element = psiFile ?: psiElement\n        createContext(\n            toolWrappers, managerEx, element,\n            dialog.isProjectScopeSelected, scope\n        ).doInspections(scope)\n    }\n\n    override fun update(e: AnActionEvent) {\n        e.presentation.text = P3cBundle.getMessage(\"com.alibaba.p3c.idea.action.AliInspectionAction.text\")\n    }\n\n    companion object {\n        private val logger = Logger.getInstance(AliInspectionAction::class.java)\n\n        private fun getTitle(element: PsiElement?, isProjectScopeSelected: Boolean): String? {\n            if (element == null) {\n                return null\n            }\n            if (isProjectScopeSelected) {\n                return \"Project\"\n            }\n            if (element is PsiFileSystemItem) {\n                return VfsUtilCore.getRelativePath(element.virtualFile, element.project.baseDir)\n            }\n            return null\n        }\n\n        fun createContext(\n            toolWrapperList: List<InspectionToolWrapper<*, *>>,\n            managerEx: InspectionManagerEx, psiElement: PsiElement?,\n            projectScopeSelected: Boolean, scope: AnalysisScope\n        ):\n            GlobalInspectionContextImpl {\n            // remove last same scope content\n            val project = managerEx.project\n            val title = getTitle(psiElement, projectScopeSelected)\n            val model = InspectionProfileService.createSimpleProfile(toolWrapperList, managerEx, psiElement)\n            title?.let {\n                model.name = it\n            }\n\n            val inspectionContext = createNewGlobalContext(\n                managerEx, projectScopeSelected\n            )\n            InspectionProfileService.setExternalProfile(model, inspectionContext)\n\n            val toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.INSPECTION)\n\n            if (toolWindow != null) {\n                val contentManager = toolWindow.contentManager\n                val contentTitle = title?.let {\n                    InspectionsBundle.message(\"inspection.results.for.profile.toolwindow.title\", it, scope.shortenName)\n                }\n                val content = contentManager.contents.firstOrNull {\n                    contentTitle != null && (it.tabName == contentTitle || it.tabName.endsWith(contentTitle))\n                }\n                content?.let {\n                    contentManager.removeContent(content, true)\n                }\n            }\n\n            return inspectionContext\n        }\n\n        private fun createNewGlobalContext(\n            managerEx: InspectionManagerEx,\n            projectScopeSelected: Boolean\n        ): GlobalInspectionContextImpl {\n            return PmdGlobalInspectionContextImpl(managerEx.project, managerEx.contentManager, projectScopeSelected)\n        }\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/PmdGlobalInspectionContextImpl.kt",
    "content": "package com.alibaba.p3c.idea.action\n\nimport com.alibaba.p3c.idea.component.AliProjectComponent\nimport com.alibaba.p3c.idea.ep.InspectionActionExtensionPoint\nimport com.alibaba.p3c.idea.inspection.AliLocalInspectionToolProvider\nimport com.alibaba.p3c.idea.inspection.PmdRuleInspectionIdentify\nimport com.alibaba.p3c.idea.pmd.AliPmdProcessor\nimport com.intellij.analysis.AnalysisScope\nimport com.intellij.codeInsight.daemon.ProblemHighlightFilter\nimport com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator\nimport com.intellij.codeInspection.ex.GlobalInspectionContextImpl\nimport com.intellij.codeInspection.ui.InspectionResultsView\nimport com.intellij.concurrency.JobLauncher\nimport com.intellij.concurrency.JobLauncherImpl\nimport com.intellij.concurrency.SensitiveProgressWrapper\nimport com.intellij.diagnostic.ThreadDumper\nimport com.intellij.openapi.application.ApplicationManager\nimport com.intellij.openapi.application.ReadAction\nimport com.intellij.openapi.application.ex.ApplicationManagerEx\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.openapi.editor.Document\nimport com.intellij.openapi.progress.ProcessCanceledException\nimport com.intellij.openapi.progress.ProgressIndicator\nimport com.intellij.openapi.progress.ProgressIndicatorProvider\nimport com.intellij.openapi.progress.ProgressManager\nimport com.intellij.openapi.progress.Task.Backgroundable\nimport com.intellij.openapi.progress.impl.CoreProgressManager\nimport com.intellij.openapi.progress.util.ProgressIndicatorUtils\nimport com.intellij.openapi.project.DumbService\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.project.displayUrlRelativeToProject\nimport com.intellij.openapi.project.isProjectOrWorkspaceFile\nimport com.intellij.openapi.roots.FileIndex\nimport com.intellij.openapi.roots.ProjectRootManager\nimport com.intellij.openapi.util.Disposer\nimport com.intellij.openapi.util.EmptyRunnable\nimport com.intellij.openapi.util.NotNullLazyValue\nimport com.intellij.openapi.vfs.VirtualFile\nimport com.intellij.psi.PsiBinaryFile\nimport com.intellij.psi.PsiDocumentManager\nimport com.intellij.psi.PsiFile\nimport com.intellij.psi.PsiManager\nimport com.intellij.psi.SingleRootFileViewProvider\nimport com.intellij.psi.search.LocalSearchScope\nimport com.intellij.psi.search.SearchScope\nimport com.intellij.psi.util.PsiUtilCore\nimport com.intellij.ui.content.ContentManager\nimport com.intellij.util.ExceptionUtil\nimport com.intellij.util.IncorrectOperationException\nimport com.intellij.util.Processor\nimport com.intellij.util.ReflectionUtil\nimport com.intellij.util.containers.ContainerUtil\nimport gnu.trove.THashSet\nimport net.sourceforge.pmd.RuleViolation\nimport java.util.Queue\nimport java.util.concurrent.ArrayBlockingQueue\nimport java.util.concurrent.BlockingQueue\nimport java.util.concurrent.Future\nimport java.util.concurrent.LinkedBlockingQueue\nimport java.util.concurrent.TimeUnit.SECONDS\n\n/**\n * @date 2020/06/19\n * @author caikang\n */\nclass PmdGlobalInspectionContextImpl(\n    project: Project,\n    contentManager: NotNullLazyValue<ContentManager>,\n    private val projectScopeSelected: Boolean\n) :\n    GlobalInspectionContextImpl(project, contentManager) {\n\n    private val logger = Logger.getInstance(PmdGlobalInspectionContextImpl::class.java)\n\n    override fun runTools(scope: AnalysisScope, runGlobalToolsOnly: Boolean, isOfflineInspections: Boolean) {\n        val usedTools = usedTools\n        val hasPmdTools = usedTools.any {\n            it.tool.tool is PmdRuleInspectionIdentify\n        }\n        if (hasPmdTools) {\n            val progressIndicator =\n                ProgressIndicatorProvider.getGlobalProgressIndicator()\n                    ?: throw IncorrectOperationException(\"Must be run under progress\")\n            pmdNodeWarmUp(scope, progressIndicator, isOfflineInspections)\n        }\n        super.runTools(scope, runGlobalToolsOnly, isOfflineInspections)\n        if (myProgressIndicator.isCanceled) {\n            return\n        }\n        InspectionActionExtensionPoint.extension.extensions.forEach {\n            try {\n                it.doOnInspectionFinished(this, projectScopeSelected)\n            } catch (e: Exception) {\n                logger.warn(e)\n            }\n        }\n    }\n\n    private fun pmdNodeWarmUp(\n        scope: AnalysisScope,\n        progressIndicator: ProgressIndicator,\n        isOfflineInspections: Boolean\n    ) {\n        val aliProjectComponent = project.getComponent(AliProjectComponent::class.java)\n        // run pmd inspection\n        val processor = Processor { file: PsiFile ->\n            ProgressManager.checkCanceled()\n            val readActionSuccess =\n                DumbService.getInstance(project).tryRunReadActionInSmartMode(\n                    {\n                        if (!file.isValid) {\n                            return@tryRunReadActionInSmartMode true\n                        }\n                        val virtualFile = file.virtualFile\n                        if (!scope.contains(virtualFile)) {\n                            logger.info(file.name + \"; scope: \" + scope + \"; \" + virtualFile)\n                            return@tryRunReadActionInSmartMode true\n                        }\n                        val path = virtualFile.canonicalPath?.toLowerCase() ?: \"\"\n                        if (!path.endsWith(\".java\") && !path.endsWith(\".vm\")) {\n                            return@tryRunReadActionInSmartMode true\n                        }\n                        doPmdProcess(file, aliProjectComponent, virtualFile)\n                        true\n                    }, \"Inspect code is not available until indices are ready\"\n                )\n            if (readActionSuccess == null || !readActionSuccess) {\n                throw ProcessCanceledException()\n            }\n            true\n        }\n        val headlessEnvironment = ApplicationManager.getApplication().isHeadlessEnvironment\n        val searchScope =\n            ApplicationManager.getApplication().runReadAction<SearchScope, RuntimeException> { scope.toSearchScope() }\n        val localScopeFiles: MutableSet<VirtualFile>? = if (searchScope is LocalSearchScope) THashSet() else null\n        val filesToInspect: BlockingQueue<PsiFile> = ArrayBlockingQueue(1000)\n        val iteratingIndicator: ProgressIndicator = SensitiveProgressWrapper(progressIndicator)\n        val future: Future<*> = startIterateScopeInBackground(\n            scope,\n            localScopeFiles,\n            headlessEnvironment,\n            filesToInspect,\n            iteratingIndicator\n        ) as Future<*>\n        val dependentIndicators =\n            ReflectionUtil.getField(javaClass, this, List::class.java, \"dependentIndicators\")?.map {\n                it as ProgressIndicator\n            }?.toMutableList()\n        try {\n            val filesFailedToInspect: Queue<PsiFile> = LinkedBlockingQueue()\n            while (true) {\n                val disposable = Disposer.newDisposable()\n                val wrapper: ProgressIndicator = DaemonProgressIndicator()\n                dependentIndicators?.let {\n                    it.add(wrapper)\n                }\n                try {\n                    // avoid \"attach listener\"/\"write action\" race\n                    ApplicationManager.getApplication().runReadAction {\n                        wrapper.start()\n                        ProgressIndicatorUtils.forceWriteActionPriority(wrapper, disposable)\n                        // there is a chance we are racing with write action, in which case just registered listener might not be called, retry.\n                        if (ApplicationManagerEx.getApplicationEx().isWriteActionPending) {\n                            throw ProcessCanceledException()\n                        }\n                    }\n                    // use wrapper here to cancel early when write action start but do not affect the original indicator\n                    (JobLauncher.getInstance() as JobLauncherImpl).processQueue(\n                        filesToInspect,\n                        filesFailedToInspect,\n                        wrapper,\n                        PsiUtilCore.NULL_PSI_FILE,\n                        processor\n                    )\n                    break\n                } catch (e: ProcessCanceledException) {\n                    progressIndicator.checkCanceled()\n                    assert(\n                        isOfflineInspections || !ApplicationManager.getApplication().isReadAccessAllowed\n                    ) {\n                        \"\"\"\n                                    Must be outside read action. PCE=\n                                    ${ExceptionUtil.getThrowableText(e)}\n                                    \"\"\".trimIndent()\n                    }\n                    assert(\n                        isOfflineInspections || !ApplicationManager.getApplication().isDispatchThread\n                    ) {\n                        \"\"\"\n                                    Must be outside EDT. PCE=\n                                    ${ExceptionUtil.getThrowableText(e)}\n                                    \"\"\".trimIndent()\n                    }\n\n                    // wait for write action to complete\n                    ApplicationManager.getApplication().runReadAction(EmptyRunnable.getInstance())\n                } finally {\n                    dependentIndicators?.let {\n                        it.remove(wrapper)\n                    }\n                    Disposer.dispose(disposable)\n                }\n            }\n        } finally {\n            iteratingIndicator.cancel() // tell file scanning thread to stop\n            filesToInspect.clear() // let file scanning thread a chance to put TOMBSTONE and complete\n            try {\n                future[30, SECONDS]\n            } catch (e: java.lang.Exception) {\n                logger.error(\n                    \"\"\"\n                                Thread dump: \n                                ${ThreadDumper.dumpThreadsToString()}\n                                \"\"\".trimIndent(), e\n                )\n            }\n        }\n        ProgressManager.checkCanceled()\n    }\n\n    private fun startIterateScopeInBackground(\n        scope: AnalysisScope,\n        localScopeFiles: MutableCollection<VirtualFile>?,\n        headlessEnvironment: Boolean,\n        outFilesToInspect: BlockingQueue<in PsiFile>,\n        progressIndicator: ProgressIndicator\n    ): Future<*>? {\n        val task: Backgroundable = object : Backgroundable(project, \"Scanning Files to Inspect\") {\n            override fun run(indicator: ProgressIndicator) {\n                try {\n                    val fileIndex: FileIndex = ProjectRootManager.getInstance(project).fileIndex\n                    scope.accept { file: VirtualFile? ->\n                        ProgressManager.checkCanceled()\n                        if (isProjectOrWorkspaceFile(file!!) || !fileIndex.isInContent(file)) return@accept true\n                        val psiFile =\n                            ReadAction.compute<PsiFile?, RuntimeException> {\n                                if (project.isDisposed) throw ProcessCanceledException()\n                                val psi = PsiManager.getInstance(project).findFile(file)\n                                val document =\n                                    psi?.let { shouldProcess(it, headlessEnvironment, localScopeFiles) }\n                                if (document != null) {\n                                    return@compute psi\n                                }\n                                null\n                            }\n                        // do not inspect binary files\n                        if (psiFile != null) {\n                            try {\n                                check(!ApplicationManager.getApplication().isReadAccessAllowed) { \"Must not have read action\" }\n                                outFilesToInspect.put(psiFile)\n                            } catch (e: InterruptedException) {\n                                logger.error(e)\n                            }\n                        }\n                        ProgressManager.checkCanceled()\n                        true\n                    }\n                } catch (e: ProcessCanceledException) {\n                    // ignore, but put tombstone\n                } finally {\n                    try {\n                        outFilesToInspect.put(PsiUtilCore.NULL_PSI_FILE)\n                    } catch (e: InterruptedException) {\n                        logger.error(e)\n                    }\n                }\n            }\n        }\n        return (ProgressManager.getInstance() as CoreProgressManager).runProcessWithProgressAsynchronously(\n            task,\n            progressIndicator,\n            null\n        )\n    }\n\n    private fun shouldProcess(\n        file: PsiFile,\n        headlessEnvironment: Boolean,\n        localScopeFiles: MutableCollection<VirtualFile>?\n    ): Document? {\n        val virtualFile = file.virtualFile ?: return null\n        if (isBinary(file)) return null //do not inspect binary files\n        if (isViewClosed && !headlessEnvironment) {\n            throw ProcessCanceledException()\n        }\n        if (logger.isDebugEnabled) {\n            logger.debug(\"Running local inspections on \" + virtualFile.path)\n        }\n        if (SingleRootFileViewProvider.isTooLargeForIntelligence(virtualFile)) return null\n        if (localScopeFiles != null && !localScopeFiles.add(virtualFile)) return null\n        return if (!ProblemHighlightFilter.shouldProcessFileInBatch(file)) null else PsiDocumentManager.getInstance(\n            project\n        ).getDocument(file)\n    }\n\n    private fun isBinary(file: PsiFile): Boolean {\n        return file is PsiBinaryFile || file.fileType.isBinary\n    }\n\n    private fun doPmdProcess(\n        file: PsiFile,\n        aliProjectComponent: AliProjectComponent,\n        virtualFile: VirtualFile\n    ) {\n        val url: String = displayUrlRelativeToProject(\n            virtualFile,\n            virtualFile.presentableUrl,\n            project,\n            true,\n            false\n        )\n        myProgressIndicator.text = \"PMD Process in $url\"\n        val violations =\n            AliPmdProcessor(AliLocalInspectionToolProvider.getRuleSets()).processFile(\n                file,\n                false\n            )\n        val fileContext = aliProjectComponent.getFileContext(virtualFile)\n        fileContext?.let { fc ->\n            val ruleViolations = ContainerUtil.createConcurrentSoftValueMap<String, List<RuleViolation>>()\n            for (entry in violations.groupBy {\n                it.rule.name\n            }) {\n                ruleViolations[entry.key] = entry.value\n            }\n            fc.ruleViolations = ruleViolations\n        }\n    }\n\n    override fun close(noSuspiciousCodeFound: Boolean) {\n        super.close(noSuspiciousCodeFound)\n        InspectionActionExtensionPoint.extension.extensions.forEach {\n            try {\n                it.doOnClose(noSuspiciousCodeFound, project)\n            } catch (e: Exception) {\n                logger.warn(e)\n            }\n        }\n    }\n\n    override fun addView(view: InspectionResultsView) {\n        super.addView(view)\n        InspectionActionExtensionPoint.extension.extensions.forEach {\n            try {\n                it.doOnView(view)\n            } catch (e: Exception) {\n                logger.warn(e)\n            }\n        }\n    }\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/SwitchLanguageAction.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.action\n\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.smartfox.idea.common.util.BalloonNotifications\nimport com.alibaba.smartfox.idea.common.util.getService\nimport com.intellij.notification.NotificationListener\nimport com.intellij.openapi.actionSystem.AnAction\nimport com.intellij.openapi.actionSystem.AnActionEvent\nimport com.intellij.openapi.application.ex.ApplicationManagerEx\nimport com.intellij.openapi.project.DumbAware\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/20\n */\nclass SwitchLanguageAction : AnAction(), DumbAware {\n    private val p3cConfig = P3cConfig::class.java.getService()\n\n    private val textKey = \"com.alibaba.p3c.action.switch_language.text\"\n\n    override fun actionPerformed(e: AnActionEvent) {\n        p3cConfig.toggleLanguage()\n        BalloonNotifications.showSuccessNotification(P3cBundle.getMessage(\"$textKey.success\"), e.project,\n                NotificationListener { notification, _ ->\n                    notification.expire()\n                    ApplicationManagerEx.getApplicationEx().restart(false)\n                }, sticky = true)\n    }\n\n    override fun update(e: AnActionEvent) {\n        e.presentation.text = P3cBundle.getMessage(\"$textKey.cur_${p3cConfig.locale}\")\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/ToggleProjectInspectionAction.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.action\n\nimport com.alibaba.p3c.idea.compatible.inspection.InspectionProfileService\nimport com.alibaba.p3c.idea.compatible.inspection.Inspections\nimport com.alibaba.p3c.idea.config.SmartFoxProjectConfig\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.inspection.AliBaseInspection\nimport com.intellij.openapi.actionSystem.AnAction\nimport com.intellij.openapi.actionSystem.AnActionEvent\nimport com.intellij.openapi.components.ServiceManager\nimport icons.P3cIcons\n\n/**\n *\n * Open or close inspections\n * @author caikang\n * @date 2017/03/14\n4\n */\nclass ToggleProjectInspectionAction : AnAction() {\n    val textKey = \"com.alibaba.p3c.idea.action.ToggleProjectInspectionAction.text\"\n\n    override fun actionPerformed(e: AnActionEvent) {\n        val project = e.project ?: return\n        val smartFoxConfig = ServiceManager.getService(project, SmartFoxProjectConfig::class.java)\n        val tools = Inspections.aliInspections(project) {\n            it.tool is AliBaseInspection\n        }\n        InspectionProfileService.toggleInspection(project, tools, smartFoxConfig.projectInspectionClosed)\n        smartFoxConfig.projectInspectionClosed = !smartFoxConfig.projectInspectionClosed\n    }\n\n    override fun update(e: AnActionEvent) {\n        val project = e.project ?: return\n        val smartFoxConfig = ServiceManager.getService(project, SmartFoxProjectConfig::class.java)\n        e.presentation.text = if (smartFoxConfig.projectInspectionClosed) {\n            e.presentation.icon = P3cIcons.PROJECT_INSPECTION_ON\n            P3cBundle.getMessage(\"$textKey.open\")\n        } else {\n            e.presentation.icon = P3cIcons.PROJECT_INSPECTION_OFF\n            P3cBundle.getMessage(\"$textKey.close\")\n        }\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/compatible/inspection/InspectionProfileService.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.compatible.inspection\n\nimport com.alibaba.smartfox.idea.common.util.PluginVersions\nimport com.google.common.collect.Sets\nimport com.intellij.codeInspection.ex.GlobalInspectionContextImpl\nimport com.intellij.codeInspection.ex.InspectionManagerEx\nimport com.intellij.codeInspection.ex.InspectionProfileImpl\nimport com.intellij.codeInspection.ex.InspectionToolWrapper\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.util.InvalidDataException\nimport com.intellij.openapi.util.WriteExternalException\nimport com.intellij.profile.codeInspection.InspectionProjectProfileManager\nimport com.intellij.psi.PsiElement\nimport org.jdom.Element\nimport java.util.LinkedHashSet\n\n/**\n *\n *\n * @author caikang\n * @date 2017/03/01\n */\nobject InspectionProfileService {\n    fun createSimpleProfile(toolWrapperList: List<InspectionToolWrapper<*, *>>,\n            managerEx: InspectionManagerEx, psiElement: PsiElement?): InspectionProfileImpl {\n        val profile = getProjectInspectionProfile(managerEx.project)\n        val allWrappers: LinkedHashSet<InspectionToolWrapper<*, *>> = Sets.newLinkedHashSet()\n        allWrappers.addAll(toolWrapperList)\n        val forCompile = allWrappers\n        for (toolWrapper in allWrappers) {\n            profile.collectDependentInspections(toolWrapper, forCompile, managerEx.project)\n        }\n        val model = when (PluginVersions.baseVersion) {\n            in PluginVersions.baseVersion171..Int.MAX_VALUE -> {\n                val clz = Class.forName(\"com.intellij.codeInspection.ex.InspectionProfileKt\")\n                val method = clz.methods.first { it.name == \"createSimple\" }\n                method.invoke(null, \"Alibaba Coding Guidelines\", managerEx.project, allWrappers.toList())\n                        as InspectionProfileImpl\n            }\n            PluginVersions.baseVersion163 -> {\n                val method = profile.javaClass.methods.first {\n                    it.name == \"createSimple\"\n                }\n                method.invoke(null, \"Alibaba Coding Guidelines\", managerEx.project, allWrappers.toList())\n                        as InspectionProfileImpl\n            }\n            else -> {\n                val method = profile.javaClass.methods.first {\n                    it.name == \"createSimple\"\n                }\n                method.invoke(null, \"Alibaba Coding Guidelines\", managerEx.project, allWrappers.toTypedArray())\n                        as InspectionProfileImpl\n            }\n        }\n        try {\n            val element = Element(\"toCopy\")\n            for (wrapper in allWrappers) {\n                wrapper.tool.writeSettings(element)\n                val tw = if (psiElement == null) {\n                    model.getInspectionTool(wrapper.shortName, managerEx.project)\n                } else {\n                    model.getInspectionTool(wrapper.shortName, psiElement)\n                }\n                tw!!.tool.readSettings(element)\n            }\n        } catch (ignored: WriteExternalException) {\n        } catch (ignored: InvalidDataException) {\n        }\n        return model\n    }\n\n    fun toggleInspection(project: Project, aliInspections: List<InspectionToolWrapper<*, *>>, closed: Boolean) {\n        val profile = getProjectInspectionProfile(project)\n        val shortNames = aliInspections.map {\n            it.tool.shortName\n        }\n        profile.removeScopes(shortNames, \"AlibabaCodeAnalysis\", project)\n        val method = profile.javaClass.methods.first {\n            it.name == if (closed) {\n                \"enableToolsByDefault\"\n            } else {\n                \"disableToolByDefault\"\n            }\n        }\n        method.invoke(profile, shortNames, project)\n        profile.profileChanged()\n        profile.scopesChanged()\n    }\n\n    fun setExternalProfile(profile: InspectionProfileImpl,\n            inspectionContext: GlobalInspectionContextImpl) {\n        val method = inspectionContext.javaClass.methods.first {\n            it.name == \"setExternalProfile\" && it.parameterTypes.size == 1 && it.parameterTypes.first().isAssignableFrom(InspectionProfileImpl::class.java)\n        }\n        method.invoke(inspectionContext, profile)\n    }\n\n    fun getProjectInspectionProfile(project: Project): InspectionProfileImpl {\n        return InspectionProjectProfileManager.getInstance(project).inspectionProfile as InspectionProfileImpl\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/compatible/inspection/Inspections.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.compatible.inspection\n\nimport com.google.common.base.Splitter\nimport com.intellij.codeInspection.ex.InspectionProfileImpl\nimport com.intellij.codeInspection.ex.InspectionToolWrapper\nimport com.intellij.codeInspection.ex.ScopeToolState\nimport com.intellij.codeInspection.javaDoc.JavaDocLocalInspection\nimport com.intellij.openapi.project.Project\n\n/**\n *\n *\n * @author caikang\n * @date 2017/03/01\n */\nobject Inspections {\n    fun aliInspections(project: Project, filter: (InspectionToolWrapper<*, *>) -> Boolean): List<InspectionToolWrapper<*, *>> {\n        val profile = InspectionProfileService.getProjectInspectionProfile(project)\n        return getAllTools(project, profile).filter(filter)\n    }\n\n    fun addCustomTag(project: Project, tag: String) {\n        val profile = InspectionProfileService.getProjectInspectionProfile(project)\n        val javaDocLocalInspection = profile.getInspectionTool(\"JavaDoc\", project)?.tool\n                as? JavaDocLocalInspection ?: return\n        if (javaDocLocalInspection.myAdditionalJavadocTags.isEmpty()) {\n            javaDocLocalInspection.myAdditionalJavadocTags = tag\n            return\n        }\n\n        val tags = Splitter.on(',').splitToList(javaDocLocalInspection.myAdditionalJavadocTags)\n        if (tags.contains(tag)) {\n            return\n        }\n        javaDocLocalInspection.myAdditionalJavadocTags += \",\" + tag\n        profile.profileChanged()\n        profile.scopesChanged()\n    }\n\n    private fun getAllTools(project: Project, profile: InspectionProfileImpl): List<InspectionToolWrapper<*, *>> {\n        val method = InspectionProfileImpl::class.java.methods.first {\n            it.name == \"getAllTools\"\n        }\n\n        val result = if (method.parameterTypes.isNotEmpty()) {\n            method.invoke(profile, project)\n        } else {\n            method.invoke(profile)\n        }\n        return (result as List<ScopeToolState>).map { it.tool }\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/component/AliProjectComponent.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.component\n\nimport com.alibaba.p3c.idea.compatible.inspection.Inspections\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.inspection.AliPmdInspectionInvoker\nimport com.alibaba.p3c.idea.pmd.SourceCodeProcessor\nimport com.alibaba.p3c.idea.util.withLockNotInline\nimport com.alibaba.p3c.pmd.I18nResources\nimport com.alibaba.smartfox.idea.common.component.AliBaseProjectComponent\nimport com.intellij.openapi.actionSystem.ActionManager\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.vfs.VirtualFile\nimport com.intellij.openapi.vfs.VirtualFileAdapter\nimport com.intellij.openapi.vfs.VirtualFileEvent\nimport com.intellij.openapi.vfs.VirtualFileListener\nimport com.intellij.openapi.vfs.VirtualFileManager\nimport com.intellij.openapi.vfs.VirtualFileMoveEvent\nimport com.intellij.psi.PsiManager\nimport net.sourceforge.pmd.RuleViolation\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.locks.ReentrantReadWriteLock\n\n/**\n * @author caikang\n * @date 2016/12/13\n */\nclass AliProjectComponent(\n    private val project: Project,\n    val p3cConfig: P3cConfig\n) : AliBaseProjectComponent {\n    private val listener: VirtualFileListener\n    private val javaExtension = \".java\"\n    private val velocityExtension = \".vm\"\n\n    private val lock = ReentrantReadWriteLock()\n    private val readLock = lock.readLock()\n    private val writeLock = lock.writeLock()\n\n    private val fileContexts = ConcurrentHashMap<String, FileContext>()\n\n    init {\n        listener = object : VirtualFileAdapter() {\n            override fun contentsChanged(event: VirtualFileEvent) {\n                val path = getFilePath(event) ?: return\n                PsiManager.getInstance(project).findFile(event.file) ?: return\n                if (!p3cConfig.ruleCacheEnable) {\n                    AliPmdInspectionInvoker.refreshFileViolationsCache(event.file)\n                }\n                if (!p3cConfig.astCacheEnable) {\n                    SourceCodeProcessor.invalidateCache(path)\n                }\n                SourceCodeProcessor.invalidUserTrigger(path)\n                fileContexts[path]?.ruleViolations = null\n            }\n\n            override fun fileDeleted(event: VirtualFileEvent) {\n                val path = getFilePath(event)\n                path?.let {\n                    SourceCodeProcessor.invalidateCache(it)\n                    removeFileContext(it)\n                }\n                super.fileDeleted(event)\n            }\n\n            override fun fileMoved(event: VirtualFileMoveEvent) {\n                val path = getFilePath(event)\n                path?.let {\n                    SourceCodeProcessor.invalidateCache(it)\n                    removeFileContext(it)\n                }\n                super.fileMoved(event)\n            }\n\n            private fun getFilePath(event: VirtualFileEvent): String? {\n                val path = event.file.canonicalPath\n                if (path == null || !(path.endsWith(javaExtension) || path.endsWith(velocityExtension))) {\n                    return null\n                }\n                return path\n            }\n        }\n    }\n\n    override fun initComponent() {\n        I18nResources.changeLanguage(p3cConfig.locale)\n        val analyticsGroup = ActionManager.getInstance().getAction(analyticsGroupId)\n        analyticsGroup.templatePresentation.text = P3cBundle.getMessage(analyticsGroupText)\n    }\n\n    override fun projectOpened() {\n        Inspections.addCustomTag(project, \"date\")\n        VirtualFileManager.getInstance().addVirtualFileListener(listener)\n    }\n\n    override fun projectClosed() {\n        VirtualFileManager.getInstance().removeVirtualFileListener(listener)\n    }\n\n    companion object {\n        val analyticsGroupId = \"com.alibaba.p3c.analytics.action_group\"\n        val analyticsGroupText = \"$analyticsGroupId.text\"\n    }\n\n    data class FileContext(\n        val lock: ReentrantReadWriteLock,\n        var ruleViolations: Map<String, List<RuleViolation>>? = null\n    )\n\n    fun removeFileContext(path: String) {\n        fileContexts.remove(path)\n    }\n\n    fun getFileContext(virtualFile: VirtualFile?): FileContext? {\n        val file = virtualFile?.canonicalPath ?: return null\n        val result = readLock.withLockNotInline {\n            fileContexts[file]\n        }\n        if (result != null) {\n            return result\n        }\n        return writeLock.withLockNotInline {\n            val finalContext = fileContexts[file]\n            if (finalContext != null) {\n                return@withLockNotInline finalContext\n            }\n            val lock = ReentrantReadWriteLock()\n            FileContext(\n                lock = lock\n            ).also {\n                fileContexts[file] = it\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/component/CommonSettingsApplicationComponent.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.component\n\nimport com.alibaba.p3c.idea.util.HighlightInfoTypes\nimport com.alibaba.p3c.idea.util.HighlightSeverities\nimport com.alibaba.smartfox.idea.common.component.AliBaseApplicationComponent\nimport com.intellij.codeInsight.daemon.impl.SeverityRegistrar\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/19\n */\nclass CommonSettingsApplicationComponent : AliBaseApplicationComponent {\n    override fun initComponent() {\n        SeverityRegistrar.registerStandard(HighlightInfoTypes.BLOCKER, HighlightSeverities.BLOCKER)\n        SeverityRegistrar.registerStandard(HighlightInfoTypes.CRITICAL, HighlightSeverities.CRITICAL)\n        SeverityRegistrar.registerStandard(HighlightInfoTypes.MAJOR, HighlightSeverities.MAJOR)\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/config/P3cConfig.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.config\n\nimport com.intellij.openapi.components.PersistentStateComponent\nimport com.intellij.openapi.components.State\nimport com.intellij.openapi.components.Storage\nimport com.intellij.util.xmlb.XmlSerializerUtil\nimport java.util.Locale\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/19\n */\n@State(name = \"P3cConfig\", storages = [Storage(file = \"smartfox/p3c.xml\")])\nclass P3cConfig : PersistentStateComponent<P3cConfig> {\n    var astCacheTime = 1000L\n    var astCacheEnable = true\n\n    var ruleCacheTime = 1000L\n    var ruleCacheEnable = false\n\n    var analysisBeforeCheckin = false\n\n    var locale: String = \"\"\n        get() {\n            if (field.isEmpty()) {\n                val lang = Locale.getDefault().language\n                return if (lang != Locale.ENGLISH.language && lang != Locale.CHINESE.language) {\n                    Locale.ENGLISH.language\n                } else Locale.getDefault().language\n            }\n\n            return field\n        }\n\n    fun toggleLanguage() {\n        locale = if (localeEn == locale) localeZh else localeEn\n    }\n\n    override fun getState(): P3cConfig {\n        return this\n    }\n\n    override fun loadState(state: P3cConfig) {\n        XmlSerializerUtil.copyBean(state, this)\n    }\n\n    companion object {\n        val localeEn = Locale.ENGLISH.language!!\n        val localeZh = Locale.CHINESE.language!!\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/config/SmartFoxProjectConfig.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.config\n\nimport com.intellij.openapi.components.PersistentStateComponent\nimport com.intellij.openapi.components.State\nimport com.intellij.util.xmlb.XmlSerializerUtil\n\n/**\n *\n *\n * @author caikang\n * @date 2017/03/01\n */\n@State(name = \"SmartFoxProjectConfig\", storages = [com.intellij.openapi.components.Storage(file = \"smartfox_info.xml\")])\nclass SmartFoxProjectConfig : PersistentStateComponent<SmartFoxProjectConfig> {\n    var projectInspectionClosed = false\n\n    override fun getState(): SmartFoxProjectConfig? {\n        return this\n    }\n\n    override fun loadState(state: SmartFoxProjectConfig) {\n        XmlSerializerUtil.copyBean(state, this)\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/ep/InspectionActionExtensionPoint.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.ep\n\nimport com.alibaba.smartfox.idea.common.util.PluginVersions\nimport com.intellij.codeInspection.ex.GlobalInspectionContextImpl\nimport com.intellij.codeInspection.ui.InspectionResultsView\nimport com.intellij.openapi.extensions.ExtensionPointName\nimport com.intellij.openapi.project.Project\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/19\n */\ninterface InspectionActionExtensionPoint {\n    fun doOnInspectionFinished(context: GlobalInspectionContextImpl, projectScopeSelected: Boolean) {}\n    fun doOnClose(noSuspiciousCodeFound: Boolean, project: Project?) {}\n    fun doOnView(view: InspectionResultsView) {}\n\n    companion object {\n        val extension = ExtensionPointName.create<InspectionActionExtensionPoint>(\n                \"${PluginVersions.pluginId.idString}.inspectionAction\")!!\n    }\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/ep/package-info.java",
    "content": "/**\n * extension point\n *\n * @author caikang\n * @date 2017/06/19\n */\npackage com.alibaba.p3c.idea.ep;"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/i18n/P3cBundle.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.i18n\n\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.pmd.I18nResources\nimport com.alibaba.smartfox.idea.common.util.getService\nimport com.intellij.CommonBundle\nimport java.util.Locale\nimport java.util.ResourceBundle\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/20\n */\nobject P3cBundle {\n    private val p3cConfig = P3cConfig::class.java.getService()\n    private val resourceBundle = ResourceBundle.getBundle(\"messages.P3cBundle\",\n            Locale(p3cConfig.locale), I18nResources.XmlControl())\n\n    fun getMessage(key: String): String {\n        return resourceBundle.getString(key).trim()\n    }\n\n    fun message(key: String, vararg params: Any): String {\n        return CommonBundle.message(resourceBundle, key, *params).trim()\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliAccessToNonThreadSafeStaticFieldFromInstanceInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.siyeh.ig.threading.AccessToNonThreadSafeStaticFieldFromInstanceInspection\n\n/**\n * @author caikang\n * @date 2016/12/08\n */\nclass AliAccessToNonThreadSafeStaticFieldFromInstanceInspection\n    : AccessToNonThreadSafeStaticFieldFromInstanceInspection,\n        AliBaseInspection {\n    constructor()\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    init {\n        nonThreadSafeClasses.clear()\n        nonThreadSafeClasses.add(\"java.text.SimpleDateFormat\")\n    }\n\n    override fun ruleName(): String {\n        return \"AvoidCallStaticSimpleDateFormatRule\"\n    }\n\n    override fun getDisplayName(): String {\n        return RuleInspectionUtils.getRuleMessage(ruleName())\n    }\n\n    override fun buildErrorString(vararg infos: Any): String {\n        return P3cBundle.getMessage(\"com.alibaba.p3c.idea.inspection.rule.AvoidCallStaticSimpleDateFormatRule.errMsg\")\n    }\n\n    override fun getStaticDescription(): String? {\n        return RuleInspectionUtils.getRuleStaticDescription(ruleName())\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliArrayNamingShouldHaveBracketInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiField\nimport com.intellij.psi.PsiMethod\nimport com.intellij.psi.PsiParameter\nimport com.siyeh.ig.InspectionGadgetsFix\nimport com.siyeh.ig.style.CStyleArrayDeclarationInspection\nimport javax.swing.JComponent\n\n/**\n *\n * Batch QuickFix Supported\n * @author caikang\n * @date 2017/02/26\n */\nclass AliArrayNamingShouldHaveBracketInspection : CStyleArrayDeclarationInspection, AliBaseInspection {\n    constructor()\n    /**\n     * ForJavassist\n     */\n    constructor(any: Any?) : this()\n\n    override fun ruleName(): String {\n        return \"ArrayNamingShouldHaveBracketRule\"\n    }\n\n    override fun getDisplayName(): String {\n        return RuleInspectionUtils.getRuleMessage(ruleName())\n    }\n\n    override fun getShortName(): String {\n        return \"AliArrayNamingShouldHaveBracket\"\n    }\n\n    override fun getStaticDescription(): String? {\n        return RuleInspectionUtils.getRuleStaticDescription(ruleName())\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())\n    }\n\n    override fun createOptionsPanel(): JComponent? {\n        return null\n    }\n\n    override fun buildErrorString(vararg infos: Any?): String {\n        val info = infos[0]\n        if (info is PsiMethod) {\n            return displayName\n        }\n        val choice = if (info is PsiField) 1 else if (info is PsiParameter) 2 else 3\n        return P3cBundle.message(\"com.alibaba.p3c.idea.inspection.rule.ArrayNamingShouldHaveBracketRule.errMsg\", choice)\n    }\n\n    override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {\n        val fix = super.buildFix(*infos) ?: return null\n        return DecorateInspectionGadgetsFix(fix,\n                P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.ArrayNamingShouldHaveBracketRule\"))\n    }\n\n    override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {\n        return buildFix(psiElement)\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliBaseInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiFile\n\n/**\n * @author caikang\n * @date 2016/12/08\n */\ninterface AliBaseInspection {\n\n    /**\n     * ruleName\n\n     * @return ruleName\n     */\n    fun ruleName(): String\n\n    /**\n     * display info for inspection\n\n     * @return display\n     */\n    fun getDisplayName(): String\n\n    /**\n     * group display info for inspection\n\n     * @return group display\n     */\n    fun getGroupDisplayName(): String\n\n    /**\n     * inspection enable by default\n\n     * @return true -> enable\n     */\n    fun isEnabledByDefault(): Boolean\n\n    /**\n     * default inspection level\n\n     * @return level\n     */\n    fun getDefaultLevel(): HighlightDisplayLevel\n\n    /**\n     * inspection short name\n\n     * @return shor name\n     */\n    fun getShortName(): String\n\n    fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? = null\n\n    fun manualParsePsiElement(psiFile: PsiFile, manager: InspectionManager,\n            start: Int, end: Int): PsiElement {\n        return psiFile.findElementAt(start)!!\n    }\n\n    companion object {\n        val GROUP_NAME = \"Ali-Check\"\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliControlFlowStatementWithoutBracesInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.psi.PsiElement\nimport com.siyeh.ig.InspectionGadgetsFix\nimport com.siyeh.ig.style.ControlFlowStatementWithoutBracesInspection\n\n/**\n * Batch QuickFix Supported\n * @author caikang\n * @date 2016/12/15\n */\nclass AliControlFlowStatementWithoutBracesInspection\n    : ControlFlowStatementWithoutBracesInspection,\n        AliBaseInspection {\n    constructor()\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    override fun ruleName(): String {\n        return \"NeedBraceRule\"\n    }\n\n    override fun getDisplayName(): String {\n        return RuleInspectionUtils.getRuleMessage(ruleName())\n    }\n\n    override fun buildErrorString(vararg infos: Any): String {\n        return P3cBundle.getMessage(\"com.alibaba.p3c.idea.inspection.rule.NeedBraceRule.errMsg\")\n    }\n\n    override fun getStaticDescription(): String? {\n        return RuleInspectionUtils.getRuleStaticDescription(ruleName())\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())\n    }\n\n    override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {\n        val fix = super.buildFix(*infos) ?: return null\n        return DecorateInspectionGadgetsFix(fix, P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.NeedBraceRule\"))\n    }\n\n    override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {\n        return buildFix(psiElement)\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliEqualsAvoidNullInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiExpression\nimport com.intellij.psi.PsiField\nimport com.intellij.psi.PsiFile\nimport com.intellij.psi.PsiLiteralExpression\nimport com.intellij.psi.PsiMethodCallExpression\nimport com.intellij.psi.PsiReferenceExpression\nimport com.siyeh.HardcodedMethodConstants\nimport com.siyeh.ig.BaseInspectionVisitor\nimport com.siyeh.ig.InspectionGadgetsFix\nimport com.siyeh.ig.psiutils.TypeUtils\nimport com.siyeh.ig.style.LiteralAsArgToStringEqualsInspection\nimport org.jetbrains.annotations.NonNls\n\n/**\n *\n * Batch QuickFix Supported\n * @author caikang\n * @date 2017/02/27\n */\nclass AliEqualsAvoidNullInspection : LiteralAsArgToStringEqualsInspection, AliBaseInspection {\n    constructor()\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    override fun ruleName(): String {\n        return \"EqualsAvoidNullRule\"\n    }\n\n    override fun getDisplayName(): String {\n        return RuleInspectionUtils.getRuleMessage(ruleName())\n    }\n\n    override fun buildErrorString(vararg infos: Any?): String {\n        val methodName = infos[0] as String\n        return String.format(P3cBundle.getMessage(\"com.alibaba.p3c.idea.inspection.rule.AliEqualsAvoidNull.errMsg\"),\n                methodName)\n    }\n\n    override fun getShortName(): String {\n        return \"AliEqualsAvoidNull\"\n    }\n\n    override fun getStaticDescription(): String? {\n        return RuleInspectionUtils.getRuleStaticDescription(ruleName())\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())\n    }\n\n    override fun buildVisitor(): BaseInspectionVisitor {\n        return LiteralAsArgToEqualsVisitor()\n    }\n\n    private class LiteralAsArgToEqualsVisitor : BaseInspectionVisitor() {\n\n        override fun visitMethodCallExpression(\n                expression: PsiMethodCallExpression) {\n            super.visitMethodCallExpression(expression)\n            val methodExpression = expression.methodExpression\n            @NonNls val methodName = methodExpression.referenceName\n            if (HardcodedMethodConstants.EQUALS != methodName && HardcodedMethodConstants.EQUALS_IGNORE_CASE != methodName) {\n                return\n            }\n            val argList = expression.argumentList\n            val args = argList.expressions\n            if (args.size != 1) {\n                return\n            }\n            val argument = args[0]\n            val argumentType = argument.type ?: return\n            if (argument !is PsiLiteralExpression && !isConstantField(argument)) {\n                return\n            }\n            if (!TypeUtils.isJavaLangString(argumentType)) {\n                return\n            }\n            val target = methodExpression.qualifierExpression\n            if (target is PsiLiteralExpression || isConstantField(argument)) {\n                return\n            }\n            registerError(argument, methodName)\n        }\n\n        private fun isConstantField(argument: PsiExpression): Boolean {\n            if (argument !is PsiReferenceExpression) {\n                return false\n            }\n            val psiField = argument.resolve() as? PsiField ?: return false\n            val modifierList = psiField.modifierList ?: return false\n            return modifierList.hasModifierProperty(\"final\") && modifierList.hasModifierProperty(\"static\")\n        }\n    }\n\n    override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {\n        val fix = super.buildFix(*infos) ?: return null\n        return DecorateInspectionGadgetsFix(fix,\n                P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.AliEqualsAvoidNull\"))\n    }\n\n    override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {\n        return buildFix(psiElement)\n    }\n\n    override fun manualParsePsiElement(psiFile: PsiFile, manager: InspectionManager, start: Int, end: Int): PsiElement {\n        return psiFile.findElementAt(start)!!.parent.parent\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliLocalInspectionToolProvider.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection\nimport com.alibaba.p3c.idea.inspection.standalone.AliDeprecationInspection\nimport com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection\nimport com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection\nimport com.alibaba.p3c.pmd.I18nResources\nimport com.alibaba.smartfox.idea.common.util.getService\nimport com.beust.jcommander.internal.Lists\nimport com.beust.jcommander.internal.Maps\nimport com.intellij.codeInspection.InspectionToolProvider\nimport com.intellij.codeInspection.LocalInspectionTool\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.openapi.roots.ProjectRootManager\nimport com.intellij.psi.PsiCompiledFile\nimport com.intellij.psi.PsiFile\nimport com.intellij.psi.PsiImportList\nimport com.intellij.psi.PsiJavaFile\nimport javassist.CannotCompileException\nimport javassist.ClassClassPath\nimport javassist.ClassPool\nimport javassist.CtField\nimport javassist.NotFoundException\nimport net.sourceforge.pmd.Rule\nimport net.sourceforge.pmd.RuleSet\nimport net.sourceforge.pmd.RuleSetFactory\nimport net.sourceforge.pmd.RuleSetNotFoundException\nimport net.sourceforge.pmd.RuleSets\nimport javax.annotation.Generated\n\n/**\n * @author caikang\n * @date 2016/12/16\n */\nclass AliLocalInspectionToolProvider : InspectionToolProvider {\n\n    override fun getInspectionClasses(): Array<Class<out LocalInspectionTool>> {\n        return CLASS_LIST.toTypedArray()\n    }\n\n    interface ShouldInspectChecker {\n        /**\n         * check inspect whether or not\n\n         * @param file file to inspect\n         * @return true or false\n         */\n        fun shouldInspect(file: PsiFile): Boolean\n    }\n\n    class RuleInfo(var rule: Rule, var shouldInspectChecker: ShouldInspectChecker)\n\n    companion object {\n        val ruleInfoMap: MutableMap<String, RuleInfo> = Maps.newHashMap<String, RuleInfo>()\n        private val LOGGER = Logger.getInstance(AliLocalInspectionToolProvider::class.java)\n        val ruleNames: MutableList<String> = Lists.newArrayList<String>()!!\n        private val CLASS_LIST = Lists.newArrayList<Class<LocalInspectionTool>>()\n        private val nativeInspectionToolClass = arrayListOf<Class<out LocalInspectionTool>>(\n            AliMissingOverrideAnnotationInspection::class.java,\n            AliAccessStaticViaInstanceInspection::class.java,\n            AliDeprecationInspection::class.java,\n            MapOrSetKeyShouldOverrideHashCodeEqualsInspection::class.java,\n            AliArrayNamingShouldHaveBracketInspection::class.java,\n            AliControlFlowStatementWithoutBracesInspection::class.java,\n            AliEqualsAvoidNullInspection::class.java,\n            AliLongLiteralsEndingWithLowercaseLInspection::class.java,\n            AliWrapperTypeEqualityInspection::class.java\n        )\n        val javaShouldInspectChecker = object : ShouldInspectChecker {\n            override fun shouldInspect(file: PsiFile): Boolean {\n                val basicInspect = file is PsiJavaFile && file !is PsiCompiledFile\n                if (!basicInspect) {\n                    return false\n                }\n\n                if (!validScope(file)) {\n                    return false\n                }\n\n                val importList = file.children.firstOrNull {\n                    it is PsiImportList\n                } as? PsiImportList ?: return true\n\n                return !importList.allImportStatements.any {\n                    it.text.contains(Generated::class.java.name)\n                }\n            }\n\n            private fun validScope(file: PsiFile): Boolean {\n                val virtualFile = file.virtualFile\n                val index = ProjectRootManager.getInstance(file.project).fileIndex\n                return index.isInSource(virtualFile)\n                    && !index.isInTestSourceContent(virtualFile)\n                    && !index.isInLibraryClasses(virtualFile)\n                    && !index.isInLibrarySource(virtualFile)\n            }\n        }\n\n        init {\n            I18nResources.changeLanguage(P3cConfig::class.java.getService().locale)\n            Thread.currentThread().contextClassLoader = AliLocalInspectionToolProvider::class.java.classLoader\n            initPmdInspection()\n            initNativeInspection()\n        }\n\n        private fun initNativeInspection() {\n            val pool = ClassPool.getDefault()\n            pool.insertClassPath(ClassClassPath(DelegateLocalInspectionTool::class.java))\n            nativeInspectionToolClass.forEach {\n                pool.insertClassPath(ClassClassPath(it))\n                val cc = pool.get(DelegateLocalInspectionTool::class.java.name)\n                cc.name = \"Delegate${it.simpleName}\"\n                val ctField = cc.getField(\"forJavassist\")\n                cc.removeField(ctField)\n                val itClass = pool.get(it.name)\n                val toolClass = pool.get(LocalInspectionTool::class.java.name)\n                val newField = CtField(toolClass, \"forJavassist\", cc)\n                cc.addField(newField, CtField.Initializer.byNew(itClass))\n                CLASS_LIST.add(cc.toClass() as Class<LocalInspectionTool>)\n            }\n        }\n\n        private fun initPmdInspection() {\n            for (ri in newRuleInfos()) {\n                this.ruleNames.add(ri.rule.name)\n                ruleInfoMap.put(ri.rule.name, ri)\n            }\n            val pool = ClassPool.getDefault()\n            pool.insertClassPath(ClassClassPath(DelegatePmdInspection::class.java))\n            try {\n                for (ruleInfo in ruleInfoMap.values) {\n                    val cc = pool.get(DelegatePmdInspection::class.java.name)\n                    cc.name = ruleInfo.rule.name + \"Inspection\"\n                    val ctField = cc.getField(\"ruleName\")\n                    cc.removeField(ctField)\n                    val value = \"\\\"\" + ruleInfo.rule.name + \"\\\"\"\n                    val newField = CtField.make(\"private String ruleName = $value;\", cc)\n                    cc.addField(newField, value)\n                    CLASS_LIST.add(cc.toClass() as Class<LocalInspectionTool>)\n                }\n\n            } catch (e: NotFoundException) {\n                LOGGER.error(e)\n            } catch (e: CannotCompileException) {\n                LOGGER.error(e)\n            }\n        }\n\n        private fun newRuleInfos(): List<RuleInfo> {\n            val result = Lists.newArrayList<RuleInfo>()\n            result.addAll(processForRuleSet(\"java/ali-pmd\", javaShouldInspectChecker))\n            result.addAll(processForRuleSet(\"vm/ali-other\", object : ShouldInspectChecker {\n                override fun shouldInspect(file: PsiFile): Boolean {\n                    val virtualFile = file.virtualFile ?: return false\n                    val path = virtualFile.canonicalPath\n                    return path != null && path.endsWith(\".vm\")\n                }\n            }))\n            return result\n        }\n\n        fun getRuleSet(ruleSetName: String): RuleSet {\n            val factory = RuleSetFactory()\n            return factory.createRuleSet(ruleSetName.replace(\"/\", \"-\"))\n        }\n\n        fun getRuleSetList(): List<RuleSet> {\n            return listOf(getRuleSet(\"java/ali-pmd\"), getRuleSet(\"vm/ali-other\"))\n        }\n\n        fun getRuleSets(): RuleSets {\n            return RuleSets().also { rs ->\n                for (ruleSet in getRuleSetList()) {\n                    rs.addRuleSet(ruleSet)\n                }\n            }\n        }\n\n        private fun processForRuleSet(ruleSetName: String, shouldInspectChecker: ShouldInspectChecker): List<RuleInfo> {\n            val result = Lists.newArrayList<RuleInfo>()\n            try {\n                val ruleSet = getRuleSet(ruleSetName)\n                ruleSet.rules.mapTo(result) {\n                    RuleInfo(it, shouldInspectChecker)\n                }\n            } catch (e: RuleSetNotFoundException) {\n                LOGGER.error(String.format(\"rule set %s not found for\", ruleSetName))\n            }\n\n            return result\n        }\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliLongLiteralsEndingWithLowercaseLInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiFile\nimport com.siyeh.ig.InspectionGadgetsFix\nimport com.siyeh.ig.numeric.LongLiteralsEndingWithLowercaseLInspection\n\n/**\n *\n * Batch QuickFix Supported\n * @author caikang\n * @date 2017/01/20\n */\nclass AliLongLiteralsEndingWithLowercaseLInspection : LongLiteralsEndingWithLowercaseLInspection, AliBaseInspection {\n    constructor()\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    override fun ruleName(): String {\n        return \"UpperEllRule\"\n    }\n\n    override fun getDisplayName(): String {\n        return RuleInspectionUtils.getRuleMessage(ruleName())\n    }\n\n    override fun buildErrorString(vararg infos: Any?): String {\n        return P3cBundle.getMessage(\"com.alibaba.p3c.idea.inspection.rule.AliLongLiteralsEndingWithLowercaseL.errMsg\")\n    }\n\n    override fun getShortName(): String {\n        return \"AliLongLiteralsEndingWithLowercaseL\"\n    }\n\n    override fun getStaticDescription(): String? {\n        return RuleInspectionUtils.getRuleStaticDescription(ruleName())\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())\n    }\n\n    override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {\n        val fix = super.buildFix(*infos) ?: return null\n        return DecorateInspectionGadgetsFix(fix,\n                P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.AliLongLiteralsEndingWithLowercaseL\"))\n    }\n\n    override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {\n        return buildFix(psiElement)\n    }\n\n    override fun manualParsePsiElement(psiFile: PsiFile, manager: InspectionManager, start: Int, end: Int): PsiElement {\n        return psiFile.findElementAt(start)!!.parent\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliPmdInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.inspection.AliLocalInspectionToolProvider.ShouldInspectChecker\nimport com.alibaba.p3c.idea.util.NumberConstants\nimport com.alibaba.p3c.idea.util.QuickFixes\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.LocalInspectionTool\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiFile\nimport net.sourceforge.pmd.Rule\nimport org.jetbrains.annotations.Nls\n\n/**\n * @author caikang\n * @date 2016/12/16\n */\nclass AliPmdInspection(private val ruleName: String) : LocalInspectionTool(),\n    AliBaseInspection,\n    PmdRuleInspectionIdentify {\n    override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {\n        return QuickFixes.getQuickFix(ruleName, isOnTheFly)\n    }\n\n    private val staticDescription: String = RuleInspectionUtils.getRuleStaticDescription(ruleName)\n\n    private val displayName: String\n\n    private val shouldInspectChecker: ShouldInspectChecker\n\n    private val defaultLevel: HighlightDisplayLevel\n\n    private val rule: Rule\n\n    init {\n        val ruleInfo = AliLocalInspectionToolProvider.ruleInfoMap[ruleName]!!\n        shouldInspectChecker = ruleInfo.shouldInspectChecker\n        rule = ruleInfo.rule\n        displayName = rule.message\n        defaultLevel = RuleInspectionUtils.getHighlightDisplayLevel(rule.priority)\n    }\n\n    override fun runForWholeFile(): Boolean {\n        return true\n    }\n\n    override fun checkFile(\n        file: PsiFile, manager: InspectionManager,\n        isOnTheFly: Boolean\n    ): Array<ProblemDescriptor>? {\n        if (!shouldInspectChecker.shouldInspect(file)) {\n            return null\n        }\n        return AliPmdInspectionInvoker.invokeInspection(file, manager, rule, isOnTheFly)\n    }\n\n    override fun getStaticDescription(): String? {\n        return staticDescription\n    }\n\n    override fun ruleName(): String {\n        return ruleName\n    }\n\n    @Nls\n    override fun getDisplayName(): String {\n        return displayName\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return defaultLevel\n    }\n\n    @Nls\n    override fun getGroupDisplayName(): String {\n        return AliBaseInspection.GROUP_NAME\n    }\n\n    override fun isEnabledByDefault(): Boolean {\n        return true\n    }\n\n    override fun getShortName(): String {\n\n        var shortName = \"Alibaba\" + ruleName\n        val index = shortName.lastIndexOf(\"Rule\")\n        if (index > NumberConstants.INDEX_0) {\n            shortName = shortName.substring(NumberConstants.INDEX_0, index)\n        }\n        return shortName\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliPmdInspectionInvoker.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.component.AliProjectComponent\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.pmd.AliPmdProcessor\nimport com.alibaba.p3c.idea.util.DocumentUtils.calculateLineStart\nimport com.alibaba.p3c.idea.util.DocumentUtils.calculateRealOffset\nimport com.alibaba.p3c.idea.util.ProblemsUtils\nimport com.alibaba.p3c.pmd.lang.java.rule.comment.RemoveCommentedCodeRule\nimport com.beust.jcommander.internal.Lists\nimport com.google.common.cache.Cache\nimport com.google.common.cache.CacheBuilder\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.openapi.components.ServiceManager\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.openapi.fileEditor.FileDocumentManager\nimport com.intellij.openapi.vfs.LocalFileSystem\nimport com.intellij.openapi.vfs.VirtualFile\nimport com.intellij.psi.PsiFile\nimport com.intellij.psi.PsiManager\nimport net.sourceforge.pmd.Rule\nimport net.sourceforge.pmd.RuleViolation\nimport java.util.concurrent.TimeUnit\n\n/**\n * @author caikang\n * @date 2016/12/13\n */\nclass AliPmdInspectionInvoker(\n    private val psiFile: PsiFile,\n    private val manager: InspectionManager,\n    private val rule: Rule\n) {\n    private val logger = Logger.getInstance(javaClass)\n\n    private var violations: List<RuleViolation> = emptyList()\n\n    fun doInvoke(isOnTheFly: Boolean) {\n        Thread.currentThread().contextClassLoader = javaClass.classLoader\n        val processor = AliPmdProcessor(rule)\n        val start = System.currentTimeMillis()\n        val aliProjectComponent = manager.project.getComponent(AliProjectComponent::class.java)\n        val fileContext = aliProjectComponent.getFileContext(psiFile.virtualFile)\n        val ruleViolations = fileContext?.ruleViolations\n        violations = if (isOnTheFly || ruleViolations == null) {\n            processor.processFile(psiFile, isOnTheFly)\n        } else {\n            ruleViolations[rule.name] ?: emptyList()\n        }\n        logger.debug(\n            \"elapsed ${System.currentTimeMillis() - start}ms to\" +\n                \" to apply rule ${rule.name} for file ${psiFile.virtualFile.canonicalPath}\"\n        )\n    }\n\n    fun getRuleProblems(isOnTheFly: Boolean): Array<ProblemDescriptor>? {\n        if (violations.isEmpty()) {\n            return null\n        }\n        val problemDescriptors = Lists.newArrayList<ProblemDescriptor>(violations.size)\n        for (rv in violations) {\n            val virtualFile = LocalFileSystem.getInstance().findFileByPath(rv.filename) ?: continue\n            val psiFile = PsiManager.getInstance(manager.project).findFile(virtualFile) ?: continue\n            val document = FileDocumentManager.getInstance().getDocument(virtualFile) ?: continue\n\n            val offsets = if (rv.rule.name == RemoveCommentedCodeRule::class.java.simpleName) {\n                Offsets(\n                    calculateLineStart(document, rv.beginLine),\n                    calculateLineStart(document, rv.endLine + 1) - 1\n                )\n            } else {\n                Offsets(\n                    calculateRealOffset(document, rv.beginLine, rv.beginColumn),\n                    calculateRealOffset(document, rv.endLine, rv.endColumn)\n                )\n            }\n            val errorMessage = if (isOnTheFly) {\n                rv.description\n            } else {\n                \"${rv.description} (line ${rv.beginLine})\"\n            }\n            val problemDescriptor = ProblemsUtils.createProblemDescriptorForPmdRule(\n                psiFile, manager,\n                isOnTheFly, rv.rule.name, errorMessage, offsets.start, offsets.end, rv.beginLine\n            ) ?: continue\n            problemDescriptors.add(problemDescriptor)\n        }\n        return problemDescriptors.toTypedArray()\n    }\n\n    companion object {\n        private lateinit var invokers: Cache<FileRule, AliPmdInspectionInvoker>\n        val smartFoxConfig = ServiceManager.getService(P3cConfig::class.java)!!\n\n        init {\n            reInitInvokers(smartFoxConfig.ruleCacheTime)\n        }\n\n        fun invokeInspection(\n            psiFile: PsiFile?, manager: InspectionManager, rule: Rule,\n            isOnTheFly: Boolean\n        ): Array<ProblemDescriptor>? {\n            if (psiFile == null) {\n                return null\n            }\n            val virtualFile = psiFile.virtualFile ?: return null\n            if (!smartFoxConfig.ruleCacheEnable) {\n                val invoker = AliPmdInspectionInvoker(psiFile, manager, rule)\n                invoker.doInvoke(isOnTheFly)\n                return invoker.getRuleProblems(isOnTheFly)\n            }\n            var invoker = invokers.getIfPresent(FileRule(virtualFile.canonicalPath!!, rule.name))\n            if (invoker == null) {\n                synchronized(virtualFile) {\n                    invoker = invokers.getIfPresent(virtualFile.canonicalPath!!)\n                    if (invoker == null) {\n                        invoker = AliPmdInspectionInvoker(psiFile, manager, rule)\n                        invoker!!.doInvoke(isOnTheFly)\n                        invokers.put(FileRule(virtualFile.canonicalPath!!, rule.name), invoker!!)\n                    }\n                }\n            }\n            return invoker!!.getRuleProblems(isOnTheFly)\n        }\n\n        private fun doInvokeIfPresent(filePath: String, rule: String, isOnTheFly: Boolean) {\n            invokers.getIfPresent(FileRule(filePath, rule))?.doInvoke(isOnTheFly)\n        }\n\n        fun refreshFileViolationsCache(file: VirtualFile) {\n            AliLocalInspectionToolProvider.ruleNames.forEach {\n                doInvokeIfPresent(file.canonicalPath!!, it, false)\n            }\n        }\n\n        fun reInitInvokers(expireTime: Long) {\n            invokers = CacheBuilder.newBuilder().maximumSize(500).expireAfterWrite(\n                expireTime,\n                TimeUnit.MILLISECONDS\n            ).build<FileRule, AliPmdInspectionInvoker>()!!\n        }\n    }\n}\n\ndata class FileRule(val filePath: String, val ruleName: String)\ndata class Offsets(val start: Int, val end: Int)\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliWrapperTypeEqualityInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.CommonClassNames\nimport com.intellij.psi.JavaTokenType\nimport com.intellij.psi.PsiArrayType\nimport com.intellij.psi.PsiBinaryExpression\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiExpression\nimport com.intellij.util.IncorrectOperationException\nimport com.siyeh.ig.BaseInspection\nimport com.siyeh.ig.BaseInspectionVisitor\nimport com.siyeh.ig.InspectionGadgetsFix\nimport com.siyeh.ig.PsiReplacementUtil\nimport com.siyeh.ig.fixes.EqualityToEqualsFix\nimport com.siyeh.ig.psiutils.ComparisonUtils\nimport com.siyeh.ig.psiutils.TypeUtils\nimport org.jetbrains.annotations.NonNls\n\n/**\n *\n * Batch QuickFix Supported\n * @author caikang\n * @date 2017/02/27\n */\nclass AliWrapperTypeEqualityInspection : BaseInspection, AliBaseInspection {\n    constructor()\n\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    val familyName = \"$replaceWith equals\"\n\n    override fun buildErrorString(vararg infos: Any?): String {\n        return P3cBundle.getMessage(\"com.alibaba.p3c.idea.inspection.rule.WrapperTypeEqualityRule.errMsg\")\n    }\n\n    override fun buildVisitor(): BaseInspectionVisitor {\n        return ObjectComparisonVisitor()\n    }\n\n    override fun ruleName(): String {\n        return \"WrapperTypeEqualityRule\"\n    }\n\n    override fun getDisplayName(): String {\n        return RuleInspectionUtils.getRuleMessage(ruleName())\n    }\n\n    override fun getShortName(): String {\n        return \"AliWrapperTypeEquality\"\n    }\n\n    override fun getStaticDescription(): String? {\n        return RuleInspectionUtils.getRuleStaticDescription(ruleName())\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())\n    }\n\n    public override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {\n        if (infos.isEmpty()) {\n            return DecorateInspectionGadgetsFix(EqualityToEqualsFix(), familyName)\n        }\n        val type = infos[0] as PsiArrayType\n        val componentType = type.componentType\n        val fix = ArrayEqualityFix(componentType is PsiArrayType, familyName)\n        return DecorateInspectionGadgetsFix(fix, fix.name, familyName)\n    }\n\n    private inner class ObjectComparisonVisitor : BaseInspectionVisitor() {\n        override fun visitBinaryExpression(expression: PsiBinaryExpression) {\n            if (!ComparisonUtils.isEqualityComparison(expression)) {\n                return\n            }\n            checkForWrapper(expression)\n        }\n\n        private fun checkForWrapper(expression: PsiBinaryExpression) {\n            val rhs = expression.rOperand ?: return\n            val lhs = expression.lOperand\n            if (!isWrapperType(lhs) || !isWrapperType(rhs)) {\n                return\n            }\n            registerError(expression.operationSign)\n        }\n\n        private fun isWrapperType(expression: PsiExpression): Boolean {\n            if (hasNumberType(expression)) {\n                return true\n            }\n            return TypeUtils.expressionHasTypeOrSubtype(expression, CommonClassNames.JAVA_LANG_BOOLEAN)\n                || TypeUtils.expressionHasTypeOrSubtype(expression, CommonClassNames.JAVA_LANG_CHARACTER)\n        }\n\n        private fun hasNumberType(expression: PsiExpression): Boolean {\n            return TypeUtils.expressionHasTypeOrSubtype(expression, CommonClassNames.JAVA_LANG_NUMBER)\n        }\n        /**\n         * checkForNumber end\n         */\n\n    }\n\n    private class ArrayEqualityFix(private val deepEquals: Boolean, private val familyName: String) :\n        InspectionGadgetsFix() {\n\n        override fun getName(): String {\n            if (deepEquals) {\n                return \"$replaceWith 'Arrays.deepEquals()'\"\n            } else {\n                return \"$replaceWith 'Arrays.equals()'\"\n            }\n        }\n\n        override fun getFamilyName(): String {\n            return familyName\n        }\n\n        @Throws(IncorrectOperationException::class)\n        override fun doFix(project: Project, descriptor: ProblemDescriptor) {\n            val element = descriptor.psiElement\n            val parent = element.parent as? PsiBinaryExpression ?: return\n            val tokenType = parent.operationTokenType\n            @NonNls\n            val newExpressionText = StringBuilder()\n            if (JavaTokenType.NE == tokenType) {\n                newExpressionText.append('!')\n            } else if (JavaTokenType.EQEQ != tokenType) {\n                return\n            }\n            if (deepEquals) {\n                newExpressionText.append(\"java.util.Arrays.deepEquals(\")\n            } else {\n                newExpressionText.append(\"java.util.Arrays.equals(\")\n            }\n            newExpressionText.append(parent.lOperand.text)\n            newExpressionText.append(',')\n            val rhs = parent.rOperand ?: return\n            newExpressionText.append(rhs.text)\n            newExpressionText.append(')')\n            PsiReplacementUtil.replaceExpressionAndShorten(\n                parent,\n                newExpressionText.toString()\n            )\n        }\n    }\n\n    override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {\n        val expression = psiElement.parent as? PsiBinaryExpression ?: return null\n        val rhs = expression.rOperand ?: return null\n        val lhs = expression.lOperand\n        val lhsType = lhs.type\n        if (lhsType !is PsiArrayType || rhs.type !is PsiArrayType) {\n            return buildFix()\n        }\n        return buildFix(lhsType)\n    }\n\n    companion object {\n        val replaceWith = P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.replace.with\")\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/DelegateLocalInspectionTool.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.LocalInspectionTool\nimport com.intellij.codeInspection.LocalInspectionToolSession\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiElementVisitor\nimport com.intellij.psi.PsiFile\nimport org.jetbrains.annotations.Nls\n\n/**\n *\n * @author caikang\n * @date 2017/07/19\n */\nclass DelegateLocalInspectionTool : LocalInspectionTool(), AliBaseInspection {\n\n    private val forJavassist: LocalInspectionTool? = null\n\n    private val localInspectionTool: LocalInspectionTool\n\n    init {\n        localInspectionTool = forJavassist ?: throw IllegalStateException()\n    }\n\n    override fun runForWholeFile(): Boolean {\n        return localInspectionTool.runForWholeFile()\n    }\n\n    override fun checkFile(\n        file: PsiFile, manager: InspectionManager,\n        isOnTheFly: Boolean\n    ): Array<ProblemDescriptor>? {\n        return localInspectionTool.checkFile(file, manager, isOnTheFly)\n    }\n\n    override fun getStaticDescription(): String? {\n        return localInspectionTool.staticDescription\n    }\n\n    override fun ruleName(): String {\n        return (localInspectionTool as AliBaseInspection).ruleName()\n    }\n\n    @Nls\n    override fun getDisplayName(): String {\n        return localInspectionTool.displayName\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return localInspectionTool.defaultLevel\n    }\n\n    @Nls\n    override fun getGroupDisplayName(): String {\n        return AliBaseInspection.GROUP_NAME\n    }\n\n    override fun isEnabledByDefault(): Boolean {\n        return true\n    }\n\n    override fun getShortName(): String {\n        return localInspectionTool.shortName\n    }\n\n    override fun isSuppressedFor(element: PsiElement): Boolean {\n        return localInspectionTool.isSuppressedFor(element)\n    }\n\n    override fun buildVisitor(\n        holder: ProblemsHolder, isOnTheFly: Boolean,\n        session: LocalInspectionToolSession\n    ): PsiElementVisitor {\n        if (!AliLocalInspectionToolProvider.javaShouldInspectChecker.shouldInspect(holder.file)) {\n            return PsiElementVisitor.EMPTY_VISITOR\n        }\n        return localInspectionTool.buildVisitor(holder, isOnTheFly, session)\n    }\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/DelegatePmdInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.LocalInspectionTool\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiFile\n\nimport org.jetbrains.annotations.Nls\n\n/**\n * @author caikang\n * @date 2017/02/28\n */\nclass DelegatePmdInspection : LocalInspectionTool(), AliBaseInspection, PmdRuleInspectionIdentify {\n\n    private val ruleName: String? = null\n\n    private val aliPmdInspection: AliPmdInspection\n\n    init {\n        aliPmdInspection = AliPmdInspection(ruleName!!)\n    }\n\n    override fun runForWholeFile(): Boolean {\n        return aliPmdInspection.runForWholeFile()\n    }\n\n    override fun checkFile(file: PsiFile, manager: InspectionManager,\n            isOnTheFly: Boolean): Array<ProblemDescriptor>? {\n        return aliPmdInspection.checkFile(file, manager, isOnTheFly)\n    }\n\n    override fun getStaticDescription(): String? {\n        return aliPmdInspection.staticDescription\n    }\n\n    override fun ruleName(): String {\n        return ruleName!!\n    }\n\n    @Nls\n    override fun getDisplayName(): String {\n        return aliPmdInspection.displayName\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return aliPmdInspection.defaultLevel\n    }\n\n    @Nls\n    override fun getGroupDisplayName(): String {\n        return aliPmdInspection.groupDisplayName\n    }\n\n    override fun isEnabledByDefault(): Boolean {\n        return aliPmdInspection.isEnabledByDefault\n    }\n\n    override fun getShortName(): String {\n        return aliPmdInspection.shortName\n    }\n\n    override fun isSuppressedFor(element: PsiElement): Boolean {\n        return aliPmdInspection.isSuppressedFor(element)\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/PmdRuleInspectionIdentify.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\n/**\n *\n *\n * @author caikang\n * @date 2017/03/16\n6\n */\ninterface PmdRuleInspectionIdentify {\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/RuleInspectionUtils.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection\n\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.util.HighlightDisplayLevels\nimport com.alibaba.p3c.idea.util.NumberConstants\nimport com.alibaba.p3c.pmd.I18nResources\nimport com.alibaba.smartfox.idea.common.util.getService\nimport com.google.common.base.Joiner\nimport com.google.common.collect.ImmutableMap\nimport com.google.common.collect.Lists\nimport com.google.common.collect.Maps\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.openapi.util.io.FileUtil\nimport com.intellij.util.io.URLUtil\nimport freemarker.template.Configuration\nimport freemarker.template.TemplateException\nimport net.sourceforge.pmd.Rule\nimport net.sourceforge.pmd.RulePriority\nimport net.sourceforge.pmd.RuleSetFactory\nimport net.sourceforge.pmd.RuleSetNotFoundException\nimport org.apache.commons.lang3.StringUtils\nimport java.io.File\nimport java.io.IOException\nimport java.io.StringWriter\nimport java.net.URL\nimport java.net.URLDecoder\nimport java.nio.charset.StandardCharsets\nimport java.util.jar.JarFile\nimport java.util.regex.Pattern\n\n/**\n * @author caikang\n * @date 2016/12/16\n */\nobject RuleInspectionUtils {\n\n    private val logger = Logger.getInstance(RuleInspectionUtils::class.java)\n    private val ruleSetFilePattern = Pattern.compile(\"(java|vm)/ali-.*?\\\\.xml\")\n    private val staticDescriptionTemplate = run {\n        val cfg = Configuration(Configuration.VERSION_2_3_25)\n        cfg.setClassForTemplateLoading(RuleInspectionUtils::class.java, \"/tpl\")\n        cfg.defaultEncoding = \"UTF-8\"\n        cfg.getTemplate(\"StaticDescriptionTemplate.ftl\")\n    }\n\n    private val ruleSetsPrefix = \"rulesets/\"\n\n    private val ruleStaticDescriptions: Map<String, String>\n    private val ruleMessages: Map<String, String>\n    private val displayLevelMap: Map<String, HighlightDisplayLevel>\n\n    init {\n        I18nResources.changeLanguage(P3cConfig::class.java.getService().locale)\n        val builder = ImmutableMap.builder<String, String>()\n        val messageBuilder = ImmutableMap.builder<String, String>()\n        val displayLevelBuilder = ImmutableMap.builder<String, HighlightDisplayLevel>()\n        val rules = loadAllAlibabaRule()\n        for (rule in rules) {\n            builder.put(rule.name, parseStaticDescription(rule))\n            messageBuilder.put(rule.name, rule.message)\n            displayLevelBuilder.put(rule.name, getHighlightDisplayLevel(rule.priority))\n        }\n        ruleStaticDescriptions = builder.build()\n        ruleMessages = messageBuilder.build()\n        displayLevelMap = displayLevelBuilder.build()\n    }\n\n    fun getRuleStaticDescription(ruleName: String): String {\n        return ruleStaticDescriptions[ruleName]!!\n    }\n\n    fun getHighlightDisplayLevel(ruleName: String): HighlightDisplayLevel {\n        val level = displayLevelMap[ruleName]\n\n        return level ?: HighlightDisplayLevel.WEAK_WARNING\n    }\n\n    fun getHighlightDisplayLevel(rulePriority: RulePriority): HighlightDisplayLevel {\n        when (rulePriority) {\n            RulePriority.HIGH -> return HighlightDisplayLevels.BLOCKER\n            RulePriority.MEDIUM_HIGH -> return HighlightDisplayLevels.CRITICAL\n            else -> return HighlightDisplayLevels.MAJOR\n        }\n    }\n\n    fun getRuleMessage(ruleName: String): String {\n        return ruleMessages[ruleName]!!\n    }\n\n    private fun parseStaticDescription(rule: Rule): String {\n        val writer = StringWriter()\n        try {\n            val map = Maps.newHashMap<String, Any>()\n            map.put(\"message\", StringUtils.trimToEmpty(rule.message))\n            map.put(\"description\", StringUtils.trimToEmpty(rule.description))\n            val examples = rule.examples.map {\n                it?.trim {\n                    c ->\n                    c == '\\n'\n                }\n            }\n            map.put(\"examples\", examples)\n            staticDescriptionTemplate.process(map, writer)\n        } catch (e: TemplateException) {\n            logger.error(e)\n        } catch (e: IOException) {\n            logger.error(e)\n        }\n        return writer.toString()\n    }\n\n    private fun loadAllAlibabaRule(): List<Rule> {\n        try {\n            Thread.currentThread().contextClassLoader = RuleInspectionUtils::class.java.classLoader\n            val ruleSetConfigs = findRuleSetConfigs()\n            val ruleSetFactory = RuleSetFactory()\n            val ruleSets = ruleSetFactory.createRuleSets(\n                    Joiner.on(\",\").join(ruleSetConfigs).replace(\"/\".toRegex(), \"-\"))\n            val map = Maps.newHashMap<String, Rule>()\n            ruleSets.allRuleSets\n                    .asSequence()\n                    .flatMap { it.rules.asSequence() }\n                    .forEach { map.put(it.name, it) }\n            return Lists.newArrayList(map.values)\n        } catch (e: IOException) {\n            logger.warn(\"no available alibaba rules\")\n            return emptyList()\n        } catch (e: RuleSetNotFoundException) {\n            logger.error(\"rule sets not found\", e)\n            return emptyList()\n        }\n\n    }\n\n    @Throws(IOException::class)\n    private fun findRuleSetConfigs(): List<String> {\n        val ruleSets = Lists.newArrayList<String>()\n        val enumeration = RuleInspectionUtils::class.java.classLoader.getResources(ruleSetsPrefix)\n        while (enumeration.hasMoreElements()) {\n            val url = enumeration.nextElement()\n            if (URLUtil.JAR_PROTOCOL == url.protocol) {\n                findRuleSetsFromJar(ruleSets, url)\n            } else if (URLUtil.FILE_PROTOCOL == url.protocol) {\n                findRuleSetsFromDirectory(ruleSets, url)\n            }\n        }\n        return ruleSets\n    }\n\n    @Throws(IOException::class)\n    private fun findRuleSetsFromDirectory(ruleSets: MutableList<String>, url: URL) {\n        val file = File(url.path)\n        if (file.exists() && file.isDirectory) {\n            val files = Lists.newArrayList<File>()\n            FileUtil.collectMatchedFiles(file, ruleSetFilePattern, files)\n            files.mapTo(ruleSets) { it.canonicalPath.replace(url.path, \"\").replace(\".xml\", \"\") }\n        }\n    }\n\n    @Throws(IOException::class)\n    private fun findRuleSetsFromJar(ruleSets: MutableList<String>, url: URL) {\n        logger.info(\"start to find rule sets from jar \" + url)\n        var path = URLDecoder.decode(url.path, StandardCharsets.UTF_8.name())\n        val index = path.lastIndexOf(URLUtil.JAR_SEPARATOR)\n        if (index > NumberConstants.INDEX_0) {\n            path = path.substring(\"file:\".length, index)\n        }\n        val jarFile = JarFile(path)\n        logger.info(\"create jarFile for path \" + path)\n        val jarEntries = jarFile.entries()\n        while (jarEntries.hasMoreElements()) {\n            val jarEntry = jarEntries.nextElement()\n            val subPath = jarEntry.name.replace(ruleSetsPrefix, \"\")\n            if (ruleSetFilePattern.matcher(subPath).find()) {\n                val resultPath = subPath.replace(\".xml\", \"\")\n                logger.info(\"get result rule set \" + resultPath)\n                ruleSets.add(resultPath)\n            }\n        }\n        logger.info(\"find rule sets from jar $url finished\")\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/standalone/AliAccessStaticViaInstanceInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection.standalone\n\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.inspection.AliBaseInspection\nimport com.alibaba.p3c.idea.util.HighlightDisplayLevels\nimport com.alibaba.smartfox.idea.common.util.getService\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil\nimport com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil\nimport com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil\nimport com.intellij.codeInsight.daemon.impl.quickfix.AccessStaticViaInstanceFix\nimport com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.codeInspection.accessStaticViaInstance.AccessStaticViaInstance\nimport com.intellij.psi.JavaElementVisitor\nimport com.intellij.psi.JavaResolveResult\nimport com.intellij.psi.PsiClass\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiElementVisitor\nimport com.intellij.psi.PsiMember\nimport com.intellij.psi.PsiModifier\nimport com.intellij.psi.PsiPackage\nimport com.intellij.psi.PsiReferenceExpression\nimport com.intellij.psi.PsiSubstitutor\nimport java.util.ArrayList\n\n/**\n * @author caikang\n * @date 2016/12/08\n */\nclass AliAccessStaticViaInstanceInspection : AccessStaticViaInstance, AliBaseInspection {\n    val messageKey = \"com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection\"\n\n    constructor()\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    override fun getDisplayName(): String {\n        return P3cBundle.getMessage(\"$messageKey.message\")\n    }\n\n    override fun getStaticDescription(): String? {\n        return P3cBundle.getMessage(\"$messageKey.desc\")\n    }\n\n    override fun ruleName(): String {\n        return \"AvoidAccessStaticViaInstanceRule\"\n    }\n\n    override fun getShortName(): String {\n        return \"AliAccessStaticViaInstance\"\n    }\n\n    override fun createAccessStaticViaInstanceFix(expr: PsiReferenceExpression,\n            onTheFly: Boolean,\n            result: JavaResolveResult): AccessStaticViaInstanceFix {\n        return object : AccessStaticViaInstanceFix(expr, result, onTheFly) {\n            val fixKey = \"com.alibaba.p3c.idea.quickfix.standalone.AliAccessStaticViaInstanceInspection\"\n            internal val text = calcText(result.element as PsiMember, result.substitutor)\n\n            override fun getText(): String {\n                return text\n            }\n\n            private fun calcText(member: PsiMember, substitutor: PsiSubstitutor): String {\n                val aClass = member.containingClass ?: return \"\"\n                val p3cConfig = P3cConfig::class.java.getService()\n                return when (p3cConfig.locale) {\n                    P3cConfig.localeZh -> String.format(P3cBundle.getMessage(fixKey),\n                            HighlightUtil.formatClass(aClass, false),\n                            HighlightUtil.formatClass(aClass), HighlightMessageUtil.getSymbolName(member, substitutor))\n                    else -> String.format(P3cBundle.getMessage(fixKey), HighlightUtil.formatClass(aClass),\n                            HighlightMessageUtil.getSymbolName(member, substitutor),\n                            HighlightUtil.formatClass(aClass, false))\n                }\n            }\n        }\n    }\n\n    override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {\n        return object : JavaElementVisitor() {\n            override fun visitReferenceExpression(expression: PsiReferenceExpression) {\n                checkAccessStaticMemberViaInstanceReference(expression, holder, isOnTheFly)\n            }\n        }\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return HighlightDisplayLevels.BLOCKER\n    }\n\n    private fun checkAccessStaticMemberViaInstanceReference(expr: PsiReferenceExpression, holder: ProblemsHolder,\n            onTheFly: Boolean) {\n        val result = expr.advancedResolve(false)\n        val resolved = result.element as? PsiMember ?: return\n\n        val qualifierExpression = expr.qualifierExpression ?: return\n\n        if (qualifierExpression is PsiReferenceExpression) {\n            val qualifierResolved = qualifierExpression.resolve()\n            if (qualifierResolved is PsiClass || qualifierResolved is PsiPackage) {\n                return\n            }\n        }\n        if (!resolved.hasModifierProperty(PsiModifier.STATIC)) {\n            return\n        }\n\n        val description = String.format(P3cBundle.getMessage(\n                \"$messageKey.errMsg\"),\n                \"${JavaHighlightUtil.formatType(qualifierExpression.type)}.${HighlightMessageUtil.getSymbolName(\n                        resolved, result.substitutor)}\")\n        if (!onTheFly) {\n            if (RemoveUnusedVariableUtil.checkSideEffects(qualifierExpression, null, ArrayList<PsiElement>())) {\n                holder.registerProblem(expr, description)\n                return\n            }\n        }\n        holder.registerProblem(expr, description, createAccessStaticViaInstanceFix(expr, onTheFly, result))\n    }\n\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/standalone/AliDeprecationInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection.standalone\n\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.inspection.AliBaseInspection\nimport com.alibaba.p3c.idea.util.HighlightDisplayLevels\nimport com.alibaba.smartfox.idea.common.util.getService\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.codeInspection.ProblemHighlightType\nimport com.intellij.codeInspection.ProblemsHolder\nimport com.intellij.codeInspection.deprecation.DeprecationInspection\nimport com.intellij.openapi.util.TextRange\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiElementVisitor\nimport com.intellij.psi.PsiReference\nimport org.jetbrains.annotations.Nls\nimport javax.swing.JComponent\n\n/**\n * @author caikang\n * @date 2016/12/08\n */\nclass AliDeprecationInspection : DeprecationInspection, AliBaseInspection {\n    private val messageKey = \"com.alibaba.p3c.idea.inspection.standalone.AliDeprecationInspection\"\n\n    constructor()\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    init {\n        IGNORE_INSIDE_DEPRECATED = true\n        IGNORE_ABSTRACT_DEPRECATED_OVERRIDES = false\n        IGNORE_IMPORT_STATEMENTS = false\n        IGNORE_METHODS_OF_DEPRECATED = false\n    }\n\n    override fun getDisplayName(): String {\n        return P3cBundle.getMessage(\"$messageKey.message\")\n    }\n\n    override fun ruleName(): String {\n        return \"AvoidUseDeprecationApiRule\"\n    }\n\n    override fun getShortName(): String {\n        return \"AliDeprecation\"\n    }\n\n    override fun getStaticDescription(): String? {\n        return P3cBundle.getMessage(\"$messageKey.desc\")\n    }\n\n    override fun createOptionsPanel(): JComponent? {\n        return null\n    }\n\n    override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {\n        val p3cConfig = P3cConfig::class.java.getService()\n        return when (p3cConfig.locale) {\n            P3cConfig.localeEn -> super.buildVisitor(holder, isOnTheFly)\n            else -> super.buildVisitor(DeprecationInspectionProblemsHolder(holder, isOnTheFly), isOnTheFly)\n        }\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return HighlightDisplayLevels.CRITICAL\n    }\n\n    class DeprecationInspectionProblemsHolder(private val holder: ProblemsHolder, onTheFly: Boolean) : ProblemsHolder(\n            holder.manager, holder.file, onTheFly) {\n\n        override fun registerProblem(psiElement: PsiElement,\n                @Nls descriptionTemplate: String,\n                fixes: Array<LocalQuickFix>?) {\n            holder.registerProblem(psiElement, getMessage(descriptionTemplate), *(fixes ?: emptyArray()))\n        }\n\n        override fun registerProblem(psiElement: PsiElement,\n                @Nls descriptionTemplate: String,\n                highlightType: ProblemHighlightType, fixes: Array<LocalQuickFix>?) {\n            holder.registerProblem(psiElement, getMessage(descriptionTemplate), highlightType, *(fixes ?: emptyArray()))\n        }\n\n        override fun registerProblem(reference: PsiReference, descriptionTemplate: String,\n                highlightType: ProblemHighlightType) {\n            holder.registerProblem(reference, getMessage(descriptionTemplate), highlightType)\n        }\n\n        override fun registerProblemForReference(reference: PsiReference,\n                highlightType: ProblemHighlightType, descriptionTemplate: String,\n                fixes: Array<LocalQuickFix>?) {\n            holder.registerProblemForReference(reference, highlightType, getMessage(descriptionTemplate),\n                    *(fixes ?: emptyArray()))\n        }\n\n        override fun registerProblem(psiElement: PsiElement, rangeInElement: TextRange?,\n                message: String, fixes: Array<LocalQuickFix>?) {\n            holder.registerProblem(psiElement, rangeInElement, getMessage(message), *(fixes ?: emptyArray()))\n        }\n\n        override fun registerProblem(psiElement: PsiElement, message: String,\n                highlightType: ProblemHighlightType, rangeInElement: TextRange?,\n                fixes: Array<LocalQuickFix>?) {\n            holder.registerProblem(psiElement, getMessage(message), highlightType, rangeInElement,\n                    *(fixes ?: emptyArray()))\n        }\n\n        private fun getMessage(msg: String): String {\n            return msg.replace(\"is deprecated\", \"已经过时了\").replace(\"Default constructor in\", \"默认构造函数\")\n                    .replace(\"Overrides deprecated method in\", \"重写了过时的方法\") + \" #loc\"\n        }\n    }\n\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/standalone/AliMissingOverrideAnnotationInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection.standalone\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.inspection.AliBaseInspection\nimport com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix\nimport com.alibaba.p3c.idea.util.HighlightDisplayLevels\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.psi.CommonClassNames\nimport com.intellij.psi.PsiAnonymousClass\nimport com.intellij.psi.PsiClass\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiMethod\nimport com.intellij.psi.PsiModifier\nimport com.intellij.psi.PsiModifierListOwner\nimport com.intellij.psi.util.InheritanceUtil\nimport com.siyeh.ig.BaseInspectionVisitor\nimport com.siyeh.ig.InspectionGadgetsFix\nimport com.siyeh.ig.inheritance.MissingOverrideAnnotationInspection\nimport com.siyeh.ig.psiutils.MethodUtils\nimport javax.swing.JComponent\n\n/**\n * Batch QuickFix Supported\n * @author caikang\n * @date 2016/12/08\n */\nclass AliMissingOverrideAnnotationInspection : MissingOverrideAnnotationInspection, AliBaseInspection {\n    private val messageKey = \"com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection\"\n\n    constructor()\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    init {\n        ignoreAnonymousClassMethods = false\n        ignoreObjectMethods = false\n    }\n\n    override fun getDisplayName(): String = P3cBundle.getMessage(\"$messageKey.message\")\n\n    override fun getStaticDescription(): String? = P3cBundle.getMessage(\"$messageKey.desc\")\n\n    override fun ruleName(): String = \"MissingOverrideAnnotationRule\"\n\n    override fun buildErrorString(vararg infos: Any): String = P3cBundle.getMessage(\"$messageKey.errMsg\")\n\n    override fun createOptionsPanel(): JComponent? = null\n\n    override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {\n        val fix = super.buildFix(*infos) ?: return null\n        return DecorateInspectionGadgetsFix(fix,\n            P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.standalone.AliMissingOverrideAnnotationInspection\"))\n    }\n\n    override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? = buildFix(psiElement)\n\n    override fun getDefaultLevel(): HighlightDisplayLevel = HighlightDisplayLevels.BLOCKER\n\n    override fun buildVisitor(): BaseInspectionVisitor = MissingOverrideAnnotationVisitor()\n\n    private inner class MissingOverrideAnnotationVisitor : BaseInspectionVisitor() {\n\n        override fun visitMethod(method: PsiMethod) {\n            if (method.nameIdentifier == null) {\n                return\n            }\n            if (method.isConstructor) {\n                return\n            }\n            if (method.hasModifierProperty(PsiModifier.PRIVATE) || method.hasModifierProperty(PsiModifier.STATIC)) {\n                return\n            }\n            val methodClass = method.containingClass ?: return\n            if (ignoreAnonymousClassMethods && methodClass is PsiAnonymousClass) {\n                return\n            }\n            if (hasOverrideAnnotation(method)) {\n                return\n            }\n            if (!isJdk6Override(method, methodClass) && !isJdk5Override(method, methodClass)) {\n                return\n            }\n            if (ignoreObjectMethods && (MethodUtils.isHashCode(method) ||\n                    MethodUtils.isEquals(method) ||\n                    MethodUtils.isToString(method))) {\n                return\n            }\n            registerMethodError(method)\n        }\n\n        private fun hasOverrideAnnotation(element: PsiModifierListOwner): Boolean {\n            val modifierList = element.modifierList\n            return modifierList?.findAnnotation(CommonClassNames.JAVA_LANG_OVERRIDE) != null\n        }\n\n        private fun isJdk6Override(method: PsiMethod, methodClass: PsiClass): Boolean {\n            val superMethods = method.findSuperMethods()\n            var hasSupers = false\n            for (superMethod in superMethods) {\n                val superClass = superMethod.containingClass\n                if (!InheritanceUtil.isInheritorOrSelf(methodClass, superClass, true)) {\n                    continue\n                }\n                hasSupers = true\n                if (!superMethod.hasModifierProperty(PsiModifier.PROTECTED)) {\n                    return true\n                }\n            }\n            // is override except if this is an interface method\n            // overriding a protected method in java.lang.Object\n            // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6501053\n            return hasSupers && !methodClass.isInterface\n        }\n\n        private fun isJdk5Override(method: PsiMethod, methodClass: PsiClass): Boolean {\n            val superMethods = method.findSuperMethods()\n            for (superMethod in superMethods) {\n                val superClass = superMethod.containingClass\n                if (superClass == null || !InheritanceUtil.isInheritorOrSelf(methodClass, superClass, true)) {\n                    continue\n                }\n                if (superClass.isInterface) {\n                    continue\n                }\n                if (methodClass.isInterface && superMethod.hasModifierProperty(PsiModifier.PROTECTED)) {\n                    // only true for J2SE java.lang.Object.clone(), but might\n                    // be different on other/newer java platforms\n                    continue\n                }\n                return true\n            }\n            return false\n        }\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/standalone/MapOrSetKeyShouldOverrideHashCodeEqualsInspection.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.inspection.standalone\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.alibaba.p3c.idea.inspection.AliBaseInspection\nimport com.alibaba.p3c.idea.util.HighlightDisplayLevels\nimport com.alibaba.p3c.idea.util.NumberConstants\nimport com.alibaba.p3c.idea.util.ObjectConstants\nimport com.google.common.collect.Sets\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\nimport com.intellij.ide.highlighter.JavaFileType\nimport com.intellij.psi.CommonClassNames\nimport com.intellij.psi.PsiClass\nimport com.intellij.psi.PsiClassType\nimport com.intellij.psi.PsiMethodCallExpression\nimport com.intellij.psi.PsiType\nimport com.intellij.psi.PsiTypeParameter\nimport com.intellij.psi.PsiVariable\nimport com.siyeh.ig.BaseInspection\nimport com.siyeh.ig.BaseInspectionVisitor\nimport org.jetbrains.annotations.NonNls\n\n/**\n * @author caikang\n * @date 2017/03/01\n */\nclass MapOrSetKeyShouldOverrideHashCodeEqualsInspection : BaseInspection, AliBaseInspection {\n    val messageKey = \"com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection\"\n\n    constructor()\n    /**\n     * For Javassist\n     */\n    constructor(any: Any?) : this()\n\n    override fun getDisplayName(): String {\n        return P3cBundle.getMessage(\"$messageKey.message\")\n    }\n\n    override fun getStaticDescription(): String? {\n        return P3cBundle.getMessage(\"$messageKey.desc\")\n    }\n\n    override fun buildErrorString(vararg infos: Any): String {\n        val type = infos[0] as PsiClassType\n        return String.format(P3cBundle.getMessage(\"$messageKey.errMsg\"), type.className)\n    }\n\n    override fun buildVisitor(): BaseInspectionVisitor {\n        return MapOrSetKeyVisitor()\n    }\n\n    override fun ruleName(): String {\n        return \"MapOrSetKeyShouldOverrideHashCodeEqualsRule\"\n    }\n\n    override fun getDefaultLevel(): HighlightDisplayLevel {\n        return HighlightDisplayLevels.CRITICAL\n    }\n\n    internal enum class ClassType {\n        /**\n         * parameter type is Set\n         */\n        SET,\n        MAP, OTHER;\n\n        override fun toString(): String {\n            val string = super.toString()\n            return string[0] + string.substring(1).toLowerCase()\n        }\n    }\n\n    private class MapOrSetKeyVisitor : BaseInspectionVisitor() {\n\n        private fun getClassType(aClass: PsiClass?): ClassType {\n            return isMapOrSet(aClass, Sets.newHashSet<PsiClass>())\n        }\n\n        private fun isMapOrSet(aClass: PsiClass?, visitedClasses: MutableSet<PsiClass>): ClassType {\n            if (aClass == null) {\n                return ClassType.OTHER\n            }\n            if (!visitedClasses.add(aClass)) {\n                return ClassType.OTHER\n            }\n            @NonNls\n            val className = aClass.qualifiedName\n            if (CommonClassNames.JAVA_UTIL_SET == className) {\n                return ClassType.SET\n            }\n            if (CommonClassNames.JAVA_UTIL_MAP == className) {\n                return ClassType.MAP\n            }\n            val supers = aClass.supers\n            return supers\n                    .map { isMapOrSet(it, visitedClasses) }\n                    .firstOrNull { it != ClassType.OTHER }\n                    ?: ClassType.OTHER\n        }\n\n        override fun visitVariable(variable: PsiVariable) {\n            super.visitVariable(variable)\n            val typeElement = variable.typeElement ?: return\n            val type = typeElement.type as? PsiClassType ?: return\n            val referenceElement = typeElement.innermostComponentReferenceElement ?: return\n            val aClass = type.resolve()\n\n            val collectionType = getClassType(aClass)\n            if (collectionType == ClassType.OTHER) {\n                return\n            }\n            val parameterList = referenceElement.parameterList\n            if (parameterList == null || parameterList.typeParameterElements.size == NumberConstants.INTEGER_SIZE_OR_LENGTH_0) {\n                return\n            }\n            val psiType = parameterList.typeArguments[0]\n            if (!redefineHashCodeEquals(psiType)) {\n                registerError(parameterList.typeParameterElements[0], psiType)\n            }\n        }\n\n        override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {\n            val methodExpression = expression.methodExpression\n            val qualifierExpression = methodExpression.qualifierExpression ?: return\n            val type = qualifierExpression.type as? PsiClassType ?: return\n            val aClass = type.resolve()\n\n            val collectionType = getClassType(aClass)\n            if (collectionType == ClassType.OTHER) {\n                return\n            }\n            @NonNls\n            val methodName = methodExpression.referenceName\n            if (collectionType == ClassType.SET && ObjectConstants.METHOD_NAME_ADD != methodName) {\n                return\n            }\n            if (collectionType == ClassType.MAP && ObjectConstants.METHOD_NAME_PUT != methodName) {\n                return\n            }\n            val argumentList = expression.argumentList\n            val arguments = argumentList.expressions\n            if (collectionType == ClassType.SET && arguments.size != NumberConstants.INTEGER_SIZE_OR_LENGTH_1) {\n                return\n            }\n            if (collectionType == ClassType.MAP && arguments.size != NumberConstants.INTEGER_SIZE_OR_LENGTH_2) {\n                return\n            }\n            val argument = arguments[0]\n            val argumentType = argument.type\n            if (argumentType == null || redefineHashCodeEquals(argumentType)) {\n                return\n            }\n            registerMethodCallError(expression, argumentType)\n        }\n    }\n\n    companion object {\n\n        private val skipJdkPackageJava = \"java.\"\n        private val skipJdkPackageJavax = \"javax.\"\n\n        private fun redefineHashCodeEquals(psiType: PsiType): Boolean {\n            if (psiType !is PsiClassType) {\n                return true\n            }\n            val psiClass = psiType.resolve() ?: return false\n            val skip = psiClass.containingFile == null || psiClass is PsiTypeParameter\n                    || psiClass.isEnum || psiClass.isInterface\n                    || psiClass.containingFile.fileType !is JavaFileType\n                    || psiClass.qualifiedName?.startsWith(skipJdkPackageJava) ?: false\n                    || psiClass.qualifiedName?.startsWith(skipJdkPackageJavax) ?: false\n            if (skip) {\n                return true\n            }\n            val hashCodeMethods = psiClass.findMethodsByName(ObjectConstants.METHOD_NAME_HASHCODE, false)\n            if (hashCodeMethods.size == NumberConstants.INTEGER_SIZE_OR_LENGTH_0) {\n                return false\n            }\n            val equalsMethods = psiClass.findMethodsByName(ObjectConstants.METHOD_NAME_EQUALS, false)\n            return equalsMethods.size > NumberConstants.INTEGER_SIZE_OR_LENGTH_0\n        }\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/pmd/AliPmdProcessor.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.pmd\n\nimport com.alibaba.p3c.idea.component.AliProjectComponent\nimport com.google.common.base.Throwables\nimport com.intellij.openapi.application.ex.ApplicationUtil\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.openapi.fileEditor.FileDocumentManager\nimport com.intellij.openapi.progress.ProcessCanceledException\nimport com.intellij.psi.PsiFile\nimport net.sourceforge.pmd.PMDConfiguration\nimport net.sourceforge.pmd.PMDException\nimport net.sourceforge.pmd.Report\nimport net.sourceforge.pmd.Rule\nimport net.sourceforge.pmd.RuleContext\nimport net.sourceforge.pmd.RuleSetFactory\nimport net.sourceforge.pmd.RuleSets\nimport net.sourceforge.pmd.RuleViolation\nimport net.sourceforge.pmd.RulesetsFactoryUtils\nimport net.sourceforge.pmd.util.ResourceLoader\nimport java.io.IOException\nimport java.io.StringReader\nimport net.sourceforge.pmd.SourceCodeProcessor as PmdSourceCodeProcessor\n\n/**\n * @author caikang\n * @date 2016/12/11\n */\nclass AliPmdProcessor private constructor(val rule: Rule? = null, val ruleSets: RuleSets? = null) {\n    constructor(rule: Rule) : this(rule, null)\n    constructor(ruleSets: RuleSets) : this(null, ruleSets)\n\n    private val ruleSetFactory: RuleSetFactory\n    private val configuration = PMDConfiguration()\n\n    init {\n        ruleSetFactory = RulesetsFactoryUtils.getRulesetFactory(configuration, ResourceLoader())\n    }\n\n    fun processFile(psiFile: PsiFile, isOnTheFly: Boolean): List<RuleViolation> {\n        configuration.setSourceEncoding(psiFile.virtualFile.charset.name())\n        configuration.inputPaths = psiFile.virtualFile.canonicalPath\n        val document = FileDocumentManager.getInstance().getDocument(psiFile.virtualFile) ?: return emptyList()\n        val project = psiFile.project\n        val aliProjectComponent = project.getComponent(AliProjectComponent::class.java)\n        val fileContext = aliProjectComponent.getFileContext(psiFile.virtualFile) ?: return emptyList()\n        val ctx = RuleContext()\n        val niceFileName = psiFile.virtualFile.canonicalPath!!\n        val report = Report.createReport(ctx, niceFileName)\n        val processRuleSets = ruleSets ?: RuleSets().also { rs ->\n            val ruleSet = ruleSetFactory.createSingleRuleRuleSet(rule)\n            rs.addRuleSet(ruleSet)\n        }\n\n\n        LOG.debug(\"Processing \" + ctx.sourceCodeFilename)\n        try {\n            val reader = StringReader(document.text)\n            ctx.languageVersion = null\n            if (isOnTheFly) {\n                SourceCodeProcessor(configuration, document, fileContext, isOnTheFly).processSourceCode(\n                    reader,\n                    processRuleSets,\n                    ctx\n                )\n            } else {\n                PmdSourceCodeProcessor(configuration).processSourceCode(reader, processRuleSets, ctx)\n            }\n        } catch (pmde: PMDException) {\n            LOG.debug(\"Error while processing file: $niceFileName\", pmde.cause)\n            report.addError(Report.ProcessingError(pmde, niceFileName))\n        } catch (ioe: IOException) {\n            LOG.error(\"Unable to read source file: $niceFileName\", ioe)\n        } catch (pce: ProcessCanceledException) {\n            throw pce\n        } catch (re: RuntimeException) {\n            val root = Throwables.getRootCause(re)\n            if (root !is ApplicationUtil.CannotRunReadActionException) {\n                LOG.error(\"RuntimeException while processing file: $niceFileName\", re)\n            }\n        }\n        return ctx.report.toList()\n    }\n\n    companion object {\n        private val LOG = Logger.getInstance(AliPmdProcessor::class.java)\n    }\n\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/pmd/SourceCodeProcessor.kt",
    "content": "/**\n * BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n */\n\npackage com.alibaba.p3c.idea.pmd\n\nimport com.alibaba.p3c.idea.component.AliProjectComponent.FileContext\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.util.withLockNotInline\nimport com.alibaba.p3c.idea.util.withTryLock\nimport com.google.common.cache.Cache\nimport com.google.common.cache.CacheBuilder\nimport com.intellij.openapi.components.ServiceManager\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.openapi.editor.Document\nimport net.sourceforge.pmd.PMD\nimport net.sourceforge.pmd.PMDConfiguration\nimport net.sourceforge.pmd.PMDException\nimport net.sourceforge.pmd.RuleContext\nimport net.sourceforge.pmd.RuleSets\nimport net.sourceforge.pmd.benchmark.TimeTracker\nimport net.sourceforge.pmd.benchmark.TimedOperationCategory\nimport net.sourceforge.pmd.lang.Language\nimport net.sourceforge.pmd.lang.LanguageVersion\nimport net.sourceforge.pmd.lang.LanguageVersionHandler\nimport net.sourceforge.pmd.lang.Parser\nimport net.sourceforge.pmd.lang.ast.Node\nimport net.sourceforge.pmd.lang.ast.ParseException\nimport java.io.Reader\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.TimeUnit.MILLISECONDS\n\nclass SourceCodeProcessor(\n    private val configuration: PMDConfiguration,\n    private val document: Document,\n    private val fileContext: FileContext,\n    private val isOnTheFly: Boolean\n) {\n\n    /**\n     * Processes the input stream against a rule set using the given input\n     * encoding. If the LanguageVersion is `null` on the RuleContext,\n     * it will be automatically determined. Any code which wishes to process\n     * files for different Languages, will need to be sure to either properly\n     * set the Language on the RuleContext, or set it to `null`\n     * first.\n     *\n     * @see RuleContext.setLanguageVersion\n     * @see PMDConfiguration.getLanguageVersionOfFile\n     * @param sourceCode\n     * The Reader to analyze.\n     * @param ruleSets\n     * The collection of rules to process against the file.\n     * @param ctx\n     * The context in which PMD is operating.\n     * @throws PMDException\n     * if the input encoding is unsupported, the input stream could\n     * not be parsed, or other error is encountered.\n     */\n    @Throws(PMDException::class)\n    fun processSourceCode(sourceCode: Reader, ruleSets: RuleSets, ctx: RuleContext) {\n        determineLanguage(ctx)\n        try {\n            ruleSets.start(ctx)\n            processSource(sourceCode, ruleSets, ctx)\n        } catch (pe: ParseException) {\n            configuration.analysisCache.analysisFailed(ctx.sourceCodeFile)\n            throw PMDException(\"Error while parsing \" + ctx.sourceCodeFilename, pe)\n        } catch (e: Exception) {\n            configuration.analysisCache.analysisFailed(ctx.sourceCodeFile)\n            throw PMDException(\"Error while processing \" + ctx.sourceCodeFilename, e)\n        } finally {\n            ruleSets.end(ctx)\n        }\n    }\n\n    private fun parse(ctx: RuleContext, sourceCode: Reader, parser: Parser): Node {\n        TimeTracker.startOperation(TimedOperationCategory.PARSER).use {\n            val rootNode = parser.parse(ctx.sourceCodeFilename, sourceCode)\n            ctx.report.suppress(parser.suppressMap)\n            return rootNode\n        }\n    }\n\n    private fun getRootNode(sourceCode: Reader, ruleSets: RuleSets, ctx: RuleContext): Node? {\n        if (!smartFoxConfig.astCacheEnable) {\n            return parseNode(ctx, ruleSets, sourceCode)\n        }\n        val node = getNode(ctx.sourceCodeFilename, isOnTheFly)\n        if (node != null) {\n            return node\n        }\n        if (document.lineCount > 3000 && isOnTheFly) {\n            return null\n        }\n        val lock = fileContext.lock\n        val readLock = lock.readLock()\n        val writeLock = lock.writeLock()\n        val ruleName = ruleSets.allRules.joinToString(\",\") { it.name }\n        val fileName = ctx.sourceCodeFilename\n        val readAction = {\n            getNode(ctx.sourceCodeFilename, isOnTheFly)\n        }\n        val cacheNode = if (isOnTheFly) {\n            readLock.withTryLock(50, MILLISECONDS, readAction)\n        } else {\n            val start = System.currentTimeMillis()\n            LOG.info(\"rule:$ruleName,file:$fileName require read lock\")\n            readLock.withLockNotInline(readAction).also {\n                LOG.info(\"rule:$ruleName,file:$fileName get result $it with read lock ,elapsed ${System.currentTimeMillis() - start}\")\n            }\n        }\n        if (cacheNode != null) {\n            return cacheNode\n        }\n        val writeAction = {\n            val finalNode = getNode(ctx.sourceCodeFilename, isOnTheFly)\n            if (finalNode == null) {\n                val start = System.currentTimeMillis()\n                if (!isOnTheFly) {\n                    LOG.info(\"rule:$ruleName,file:$fileName parse with write lock\")\n                }\n                parseNode(ctx, ruleSets, sourceCode).also {\n                    if (!isOnTheFly) {\n                        LOG.info(\"rule:$ruleName,file:$fileName get result $it parse with write lock ,elapsed ${System.currentTimeMillis() - start}\")\n                    }\n                }\n            } else {\n                finalNode\n            }\n        }\n        return if (isOnTheFly) {\n            writeLock.withTryLock(50, MILLISECONDS, writeAction)!!\n        } else {\n            writeLock.withLockNotInline(\n                writeAction\n            )!!\n        }\n    }\n\n    private fun parseNode(ctx: RuleContext, ruleSets: RuleSets, sourceCode: Reader): Node {\n        val languageVersion = ctx.languageVersion\n        val languageVersionHandler = languageVersion.languageVersionHandler\n        val parser = PMD.parserFor(languageVersion, configuration)\n        val rootNode = parse(ctx, sourceCode, parser)\n        symbolFacade(rootNode, languageVersionHandler)\n        val language = languageVersion.language\n        usesDFA(languageVersion, rootNode, ruleSets, language)\n        usesTypeResolution(languageVersion, rootNode, ruleSets, language)\n        onlyTheFlyCache.put(ctx.sourceCodeFilename, rootNode)\n        userTriggerNodeCache.put(ctx.sourceCodeFilename, rootNode)\n        return rootNode\n    }\n\n    private fun symbolFacade(rootNode: Node, languageVersionHandler: LanguageVersionHandler) {\n        TimeTracker.startOperation(TimedOperationCategory.SYMBOL_TABLE)\n            .use { languageVersionHandler.getSymbolFacade(configuration.classLoader).start(rootNode) }\n    }\n\n    private fun resolveQualifiedNames(rootNode: Node, handler: LanguageVersionHandler) {\n        TimeTracker.startOperation(TimedOperationCategory.QUALIFIED_NAME_RESOLUTION)\n            .use { handler.getQualifiedNameResolutionFacade(configuration.classLoader).start(rootNode) }\n    }\n\n    // private ParserOptions getParserOptions(final LanguageVersionHandler\n    // languageVersionHandler) {\n    // // TODO Handle Rules having different parser options.\n    // ParserOptions parserOptions =\n    // languageVersionHandler.getDefaultParserOptions();\n    // parserOptions.setSuppressMarker(configuration.getSuppressMarker());\n    // return parserOptions;\n    // }\n\n    private fun usesDFA(languageVersion: LanguageVersion, rootNode: Node, ruleSets: RuleSets, language: Language) {\n        if (ruleSets.usesDFA(language)) {\n            TimeTracker.startOperation(TimedOperationCategory.DFA).use { to ->\n                val dataFlowFacade = languageVersion.languageVersionHandler.dataFlowFacade\n                dataFlowFacade.start(rootNode)\n            }\n        }\n    }\n\n    private fun usesTypeResolution(\n        languageVersion: LanguageVersion, rootNode: Node, ruleSets: RuleSets,\n        language: Language\n    ) {\n\n        if (ruleSets.usesTypeResolution(language)) {\n            TimeTracker.startOperation(TimedOperationCategory.TYPE_RESOLUTION).use { to ->\n                languageVersion.languageVersionHandler.getTypeResolutionFacade(configuration.classLoader)\n                    .start(rootNode)\n            }\n        }\n    }\n\n    private fun usesMultifile(\n        rootNode: Node, languageVersionHandler: LanguageVersionHandler, ruleSets: RuleSets,\n        language: Language\n    ) {\n\n        if (ruleSets.usesMultifile(language)) {\n            TimeTracker.startOperation(TimedOperationCategory.MULTIFILE_ANALYSIS)\n                .use { languageVersionHandler.multifileFacade.start(rootNode) }\n        }\n    }\n\n    private fun processSource(sourceCode: Reader, ruleSets: RuleSets, ctx: RuleContext) {\n        val languageVersion = ctx.languageVersion\n        val languageVersionHandler = languageVersion.languageVersionHandler\n\n        val rootNode = getRootNode(sourceCode, ruleSets, ctx) ?: return\n        resolveQualifiedNames(rootNode, languageVersionHandler)\n        symbolFacade(rootNode, languageVersionHandler)\n        val language = languageVersion.language\n        usesDFA(languageVersion, rootNode, ruleSets, language)\n        usesTypeResolution(languageVersion, rootNode, ruleSets, language)\n        usesMultifile(rootNode, languageVersionHandler, ruleSets, language)\n\n        val acus = listOf(rootNode)\n        ruleSets.apply(acus, ctx, language)\n    }\n\n    private fun determineLanguage(ctx: RuleContext) {\n        // If LanguageVersion of the source file is not known, make a\n        // determination\n        if (ctx.languageVersion == null) {\n            val languageVersion = configuration.getLanguageVersionOfFile(ctx.sourceCodeFilename)\n            ctx.languageVersion = languageVersion\n        }\n    }\n\n    companion object {\n        val smartFoxConfig = ServiceManager.getService(P3cConfig::class.java)!!\n        private lateinit var onlyTheFlyCache: Cache<String, Node>\n        private lateinit var userTriggerNodeCache: Cache<String, Node>\n        private val LOG = Logger.getInstance(SourceCodeProcessor::class.java)\n\n        init {\n            reInitNodeCache(smartFoxConfig.astCacheTime)\n        }\n\n        fun reInitNodeCache(expireTime: Long) {\n            onlyTheFlyCache = CacheBuilder.newBuilder().concurrencyLevel(16)\n                .expireAfterWrite(expireTime, TimeUnit.MILLISECONDS)\n                .maximumSize(300)\n                .build<String, Node>()!!\n\n            userTriggerNodeCache = CacheBuilder.newBuilder().concurrencyLevel(16)\n                .expireAfterWrite(10, TimeUnit.MINUTES)\n                .maximumSize(300)\n                .build<String, Node>()!!\n        }\n\n        fun invalidateCache(file: String) {\n            onlyTheFlyCache.invalidate(file)\n            userTriggerNodeCache.invalidate(file)\n        }\n\n        fun invalidUserTrigger(file: String) {\n            userTriggerNodeCache.invalidate(file)\n        }\n\n        fun invalidateAll() {\n            onlyTheFlyCache.invalidateAll()\n            userTriggerNodeCache.invalidateAll()\n        }\n\n        fun getNode(file: String, isOnTheFly: Boolean): Node? {\n            return if (isOnTheFly) onlyTheFlyCache.getIfPresent(file) else userTriggerNodeCache.getIfPresent(file)\n        }\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/pmd/index/InspectionDataSource.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.pmd.index\n\nimport com.intellij.util.indexing.FileContent\nimport net.sourceforge.pmd.util.datasource.DataSource\nimport java.io.ByteArrayInputStream\nimport java.io.IOException\nimport java.io.InputStream\n\n/**\n * @author caikang\n * @date 2016/12/11\n */\nclass InspectionDataSource(private val fileContent: FileContent) : DataSource {\n\n    @Throws(IOException::class)\n    override fun getInputStream(): InputStream {\n        return ByteArrayInputStream(fileContent.content)\n    }\n\n    override fun getNiceFileName(shortNames: Boolean, inputFileName: String?): String {\n        return fileContent.fileName\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/pmd/index/InspectionRenderer.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.pmd.index\n\nimport net.sourceforge.pmd.Report\nimport net.sourceforge.pmd.RuleViolation\nimport net.sourceforge.pmd.renderers.AbstractRenderer\nimport net.sourceforge.pmd.renderers.Renderer\nimport net.sourceforge.pmd.util.datasource.DataSource\nimport java.io.IOException\n\n/**\n * @author caikang\n * @date 2016/12/11\n */\nclass InspectionRenderer : AbstractRenderer(\"InspectionRenderer\", \"Idea Inspection for pmd result\"), Renderer {\n    private lateinit var ruleProblems: List<RuleViolation>\n\n    override fun defaultFileExtension(): String? {\n        return null\n    }\n\n    @Throws(IOException::class)\n    override fun start() {\n    }\n\n    override fun startFileAnalysis(dataSource: DataSource) {\n    }\n\n    @Throws(IOException::class)\n    override fun renderFileReport(report: Report) {\n        ruleProblems = report.map { it }\n    }\n\n    @Throws(IOException::class)\n    override fun end() {\n    }\n\n    fun getViolations(): List<RuleViolation> {\n        return ruleProblems\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/AliQuickFix.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.quickfix\n\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.openapi.actionSystem.ActionManager\nimport com.intellij.openapi.actionSystem.AnActionEvent\nimport com.intellij.openapi.actionSystem.CommonDataKeys\nimport com.intellij.openapi.fileEditor.FileEditorManager\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.JavaPsiFacade\nimport com.intellij.psi.PsiDocumentManager\nimport com.intellij.psi.PsiFile\nimport com.intellij.psi.PsiIdentifier\nimport com.intellij.psi.PsiLocalVariable\nimport com.intellij.psi.PsiMember\nimport com.intellij.psi.PsiParameter\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/27\n */\ninterface AliQuickFix : LocalQuickFix {\n\n    val ruleName: String\n    val onlyOnThFly: Boolean\n\n    override fun getFamilyName(): String {\n        return groupName\n    }\n\n    companion object {\n        const val groupName = \"Ali QuickFix\"\n\n        fun doQuickFix(newIdentifier: String, project: Project, psiIdentifier: PsiIdentifier) {\n            val offset = psiIdentifier.textOffset\n            val cannotFix = psiIdentifier.parent !is PsiMember\n                    && !(psiIdentifier.parent is PsiLocalVariable || psiIdentifier.parent is PsiParameter)\n            if (cannotFix) {\n                return\n            }\n\n            val editor = FileEditorManager.getInstance(project).selectedTextEditor ?: return\n            editor.caretModel.moveToOffset(psiIdentifier.textOffset)\n            val anAction = ActionManager.getInstance().getAction(\"RenameElement\")\n            val psiFile = psiIdentifier.containingFile\n            commitDocumentIfNeeded(psiFile, project)\n            val event = AnActionEvent.createFromDataContext(\"MainMenu\", anAction.templatePresentation) {\n                when (it) {\n                    CommonDataKeys.PROJECT.name -> project\n                    CommonDataKeys.EDITOR.name -> editor\n                    CommonDataKeys.PSI_FILE.name -> psiFile\n                    CommonDataKeys.PSI_ELEMENT.name -> psiIdentifier.parent\n                    else -> null\n                }\n            }\n            val psiFacade = JavaPsiFacade.getInstance(project)\n            val factory = psiFacade.elementFactory\n\n            anAction.actionPerformed(event)\n\n            // origin PsiIdentifier is unavailable\n            psiFile.findElementAt(offset)?.replace(factory.createIdentifier(newIdentifier))\n        }\n\n        private fun commitDocumentIfNeeded(file: PsiFile?, project: Project) {\n            if (file == null) {\n                return\n            }\n            val manager = PsiDocumentManager.getInstance(project)\n            val cachedDocument = manager.getCachedDocument(file) ?: return\n            manager.commitDocument(cachedDocument)\n        }\n\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/AvoidStartWithDollarAndUnderLineNamingQuickFix.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.quickfix\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.PsiIdentifier\nimport org.apache.commons.lang3.StringUtils\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/28\n */\nobject AvoidStartWithDollarAndUnderLineNamingQuickFix : AliQuickFix {\n    override val ruleName: String\n        get() = \"AvoidStartWithDollarAndUnderLineNamingRule\"\n    override val onlyOnThFly: Boolean\n        get() = true\n\n    override fun getName(): String {\n        return P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.delete_$\")\n    }\n\n    override fun applyFix(project: Project, descriptor: ProblemDescriptor) {\n        val psiIdentifier = descriptor.psiElement as? PsiIdentifier ?: return\n        val identifier = psiIdentifier.text\n        val resultName = StringUtils.replacePattern(identifier, \"^[\\$_]+\", \"\")\n        if (resultName.toLongOrNull() != null) {\n            return\n        }\n        AliQuickFix.doQuickFix(resultName, project, psiIdentifier)\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/ClassMustHaveAuthorQuickFix.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.quickfix\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.JavaPsiFacade\nimport com.intellij.psi.PsiClass\nimport com.intellij.psi.javadoc.PsiDocToken\nimport com.siyeh.ig.InspectionGadgetsFix\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/27\n */\nobject ClassMustHaveAuthorQuickFix : InspectionGadgetsFix(), AliQuickFix {\n\n    val tag = \"@author ${System.getProperty(\"user.name\") ?: System.getenv(\"USER\")}\"\n\n    override fun doFix(project: Project?, descriptor: ProblemDescriptor?) {\n        descriptor ?: return\n        val psiClass = descriptor.psiElement as? PsiClass ?: descriptor.psiElement?.parent as? PsiClass ?: return\n\n        val document = psiClass.docComment\n        val psiFacade = JavaPsiFacade.getInstance(project)\n        val factory = psiFacade.elementFactory\n        if (document == null) {\n            val doc = factory.createDocCommentFromText(\"\"\"\n/**\n * $tag\n */\n\"\"\")\n            if (psiClass.isEnum) {\n                psiClass.containingFile.addAfter(doc, psiClass.prevSibling)\n            } else {\n                psiClass.addBefore(doc, psiClass.firstChild)\n            }\n            return\n        }\n\n        val regex = Regex(\"Created by (.*) on (.*)\\\\.\")\n        for (line in document.descriptionElements) {\n            if (line is PsiDocToken && line.text.contains(regex)) {\n                val groups = regex.find(line.text)?.groups ?: continue\n                val author = groups[1]?.value ?: continue\n                val date = groups[2]?.value ?: continue\n                document.addBefore(factory.createDocTagFromText(\"@date $date\"), line)\n                document.addBefore(factory.createDocTagFromText(\"@author $author\"), line)\n                line.delete()\n                return\n            }\n        }\n\n        if (document.tags.isNotEmpty()) {\n            document.addBefore(factory.createDocTagFromText(tag), document.tags[0])\n            return\n        }\n\n        document.add(factory.createDocTagFromText(tag))\n    }\n\n    override val ruleName: String\n        get() = \"ClassMustHaveAuthorRule\"\n    override val onlyOnThFly: Boolean\n        get() = true\n\n    override fun getName(): String {\n        return P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.generate.author\")\n    }\n\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/ConstantFieldShouldBeUpperCaseQuickFix.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.quickfix\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.google.common.base.Splitter\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.PsiIdentifier\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/28\n */\nobject ConstantFieldShouldBeUpperCaseQuickFix : AliQuickFix {\n    val separator = '_'\n\n    override fun getName(): String {\n        return P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.field.to.upperCaseWithUnderscore\")\n    }\n\n    override fun applyFix(project: Project, descriptor: ProblemDescriptor) {\n        val psiIdentifier = descriptor.psiElement as? PsiIdentifier ?: return\n        val identifier = psiIdentifier.text\n        val list = Splitter.on(separator).trimResults().omitEmptyStrings().splitToList(identifier)\n\n        val resultName = list.joinToString(separator.toString()) {\n            separateCamelCase(it).toUpperCase()\n        }\n\n        AliQuickFix.doQuickFix(resultName, project, psiIdentifier)\n    }\n\n    private fun separateCamelCase(name: String): String {\n        val translation = StringBuilder()\n\n\n        for (i in 0 until name.length - 1) {\n            val character = name[i]\n            val next = name[i + 1]\n            if (Character.isUpperCase(character) && !next.isUpperCase() && translation.isNotEmpty()) {\n                translation.append(separator)\n            }\n            if (character != separator) {\n                translation.append(character)\n            }\n        }\n        val last = name.last()\n        if (last != separator) {\n            translation.append(last)\n        }\n        return translation.toString()\n    }\n\n    override val ruleName: String\n        get() = \"ConstantFieldShouldBeUpperCaseRule\"\n    override val onlyOnThFly: Boolean\n        get() = true\n\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/DecorateInspectionFix.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.quickfix\n\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.openapi.project.Project\nimport com.siyeh.ig.InspectionGadgetsFix\n\n/**\n *\n *\n * @author caikang\n * @date 2017/03/02\n */\nclass DecorateInspectionGadgetsFix(val fix: InspectionGadgetsFix,\n        internal val name: String,\n        internal val familyName: String = name) : InspectionGadgetsFix() {\n    override fun getName(): String {\n        return name\n    }\n\n    override fun doFix(project: Project, descriptor: ProblemDescriptor) {\n        fix.applyFix(project, descriptor)\n    }\n\n\n    override fun getFamilyName(): String {\n        return familyName\n    }\n\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/LowerCamelCaseVariableNamingQuickFix.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.quickfix\n\nimport com.alibaba.p3c.idea.i18n.P3cBundle\nimport com.google.common.base.Splitter\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.openapi.project.Project\nimport com.intellij.psi.PsiIdentifier\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/28\n */\nobject LowerCamelCaseVariableNamingQuickFix : AliQuickFix {\n    override val ruleName: String\n        get() = \"LowerCamelCaseVariableNamingRule\"\n    override val onlyOnThFly: Boolean\n        get() = true\n\n    override fun getName(): String {\n        return P3cBundle.getMessage(\"com.alibaba.p3c.idea.quickfix.variable.lowerCamelCase\")\n    }\n\n    override fun applyFix(project: Project, descriptor: ProblemDescriptor) {\n        val psiIdentifier = descriptor.psiElement as? PsiIdentifier ?: return\n        val identifier = psiIdentifier.text\n        val resultName = toLowerCamelCase(identifier)\n        AliQuickFix.doQuickFix(resultName, project, psiIdentifier)\n    }\n\n    private fun toLowerCamelCase(identifier: String): String {\n        val list = Splitter.onPattern(\"[^a-z0-9A-Z]+\").trimResults()\n            .omitEmptyStrings().split(identifier).toList()\n        val result = list.mapIndexed { i, s ->\n            val charArray = s.toCharArray()\n            charArray[0] = if (i == 0) charArray[0].toLowerCase() else charArray[0].toUpperCase()\n            String(charArray)\n        }\n        return result.joinToString(\"\")\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/VmQuietReferenceQuickFix.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.quickfix\n\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.openapi.fileEditor.FileDocumentManager\nimport com.intellij.openapi.project.Project\n\n/**\n *\n *\n * @author caikang\n * @date 2017/01/26\n */\nobject VmQuietReferenceQuickFix : AliQuickFix {\n    override val onlyOnThFly: Boolean\n        get() = true\n\n    override fun applyFix(project: Project, descriptor: ProblemDescriptor) {\n        val textRange = descriptor.textRangeInElement ?: return\n        val document = FileDocumentManager.getInstance().getDocument(\n                descriptor.startElement.containingFile.virtualFile) ?: return\n        document.insertString(textRange.startOffset + 1, \"!\")\n    }\n\n    override val ruleName = \"UseQuietReferenceNotationRule\"\n\n    override fun getName(): String {\n        return \"为变量添加!\"\n    }\n\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/DocumentUtils.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.util\n\nimport com.intellij.openapi.editor.Document\nimport com.intellij.openapi.util.TextRange\n\n/**\n *\n *\n * @author caikang\n * @date 2017/03/16\n6\n */\nobject DocumentUtils {\n    private val PMD_TAB_SIZE = 8\n    fun calculateRealOffset(document: Document, line: Int, pmdColumn: Int): Int {\n        val maxLine = document.lineCount\n        if (maxLine < line) {\n            return -1\n        }\n        val lineOffset = document.getLineStartOffset(line - 1)\n        return lineOffset + calculateRealColumn(document, line, pmdColumn)\n    }\n\n    fun calculateLineStart(document: Document, line: Int): Int {\n        val maxLine = document.lineCount\n        if (maxLine < line) {\n            return -1\n        }\n        return document.getLineStartOffset(line - 1)\n    }\n\n    fun calculateRealColumn(document: Document, line: Int, pmdColumn: Int): Int {\n        var realColumn = pmdColumn - 1\n        val minusSize = PMD_TAB_SIZE - 1\n        val docLine = line - 1\n        val lineStartOffset = document.getLineStartOffset(docLine)\n        val lineEndOffset = document.getLineEndOffset(docLine)\n        val text = document.getText(TextRange(lineStartOffset, lineEndOffset))\n\n        text.forEachIndexed { i, c ->\n            if (c == '\\t') {\n                realColumn -= minusSize\n            }\n            if (i >= realColumn) {\n                return@forEachIndexed\n            }\n        }\n\n        return realColumn\n    }\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/HighlightDisplayLevels.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.util\n\nimport com.intellij.codeHighlighting.HighlightDisplayLevel\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/04\n */\nobject HighlightDisplayLevels {\n    val BLOCKER = HighlightDisplayLevel(HighlightSeverities.BLOCKER, HighlightDisplayLevel.ERROR.icon)\n    val CRITICAL = HighlightDisplayLevel(HighlightSeverities.CRITICAL, HighlightDisplayLevel.WARNING.icon)\n    val MAJOR = HighlightDisplayLevel(HighlightSeverities.MAJOR, HighlightDisplayLevel.WEAK_WARNING.icon)\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/HighlightInfoTypes.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.util\n\nimport com.intellij.codeInsight.daemon.impl.HighlightInfoType\nimport com.intellij.openapi.editor.colors.CodeInsightColors\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/04\n */\nobject HighlightInfoTypes {\n    val BLOCKER: HighlightInfoType = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverities.BLOCKER,\n            CodeInsightColors.ERRORS_ATTRIBUTES)\n    val CRITICAL: HighlightInfoType = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverities.CRITICAL,\n            CodeInsightColors.WARNINGS_ATTRIBUTES)\n    val MAJOR: HighlightInfoType = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverities.MAJOR,\n            CodeInsightColors.WEAK_WARNING_ATTRIBUTES)\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/HighlightSeverities.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.util\n\nimport com.intellij.lang.annotation.HighlightSeverity\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/04\n */\nobject HighlightSeverities {\n    val MAJOR = HighlightSeverity(\"MAJOR\", 397)\n\n\n    /**\n     * The standard severity level for warning annotations.\n     */\n    val CRITICAL = HighlightSeverity(\"CRITICAL\", 398)\n\n    /**\n     * The standard severity level for error annotations.\n     */\n    val BLOCKER = HighlightSeverity(\"BLOCKER\", 399)\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/NumberConstants.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.util\n\n/**\n * @author caikang\n * @date 2016/12/28\n */\nobject NumberConstants {\n    val INTEGER_SIZE_OR_LENGTH_0 = 0\n    val INTEGER_SIZE_OR_LENGTH_1 = 1\n    val INTEGER_SIZE_OR_LENGTH_2 = 2\n\n    val INDEX_0 = 0\n    val INDEX_1 = 1\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/ObjectConstants.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.util\n\n/**\n * @author caikang\n * @date 2016/12/28\n */\nobject ObjectConstants {\n    val METHOD_NAME_EQUALS = \"equals\"\n    val METHOD_NAME_HASHCODE = \"hashCode\"\n    val METHOD_NAME_ADD = \"add\"\n    val METHOD_NAME_PUT = \"put\"\n    val CLASS_LITERAL = \"class\"\n    val INTERFACE_LITERAL = \"interface\"\n    val ENUM_LITERAL = \"enum\"\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/ProblemsUtils.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.util\n\nimport com.alibaba.p3c.pmd.lang.java.rule.comment.AvoidCommentBehindStatementRule\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.LocalQuickFix\nimport com.intellij.codeInspection.ProblemDescriptor\nimport com.intellij.codeInspection.ProblemHighlightType\nimport com.intellij.openapi.fileEditor.FileDocumentManager\nimport com.intellij.openapi.util.TextRange\nimport com.intellij.psi.PsiClass\nimport com.intellij.psi.PsiElement\nimport com.intellij.psi.PsiField\nimport com.intellij.psi.PsiFile\nimport com.intellij.psi.PsiIdentifier\nimport com.intellij.psi.PsiJavaToken\nimport com.intellij.psi.PsiKeyword\nimport com.intellij.psi.PsiWhiteSpace\nimport com.intellij.psi.impl.source.tree.ElementType\n\n/**\n *\n *\n * @author caikang\n * @date 2017/03/16\n6\n */\nobject ProblemsUtils {\n    private val highlightLineRules = setOf(AvoidCommentBehindStatementRule::class.java.simpleName)\n\n    fun createProblemDescriptorForPmdRule(psiFile: PsiFile, manager: InspectionManager, isOnTheFly: Boolean,\n            ruleName: String, desc: String, start: Int, end: Int,\n            checkLine: Int = 0,\n            quickFix: (PsiElement) -> LocalQuickFix? = {\n                QuickFixes.getQuickFix(ruleName, isOnTheFly)\n            }): ProblemDescriptor? {\n        val document = FileDocumentManager.getInstance().getDocument(psiFile.virtualFile) ?: return null\n        if (highlightLineRules.contains(ruleName) && checkLine <= document.lineCount) {\n            val lineNumber = if (start >= document.textLength) {\n                document.lineCount - 1\n            } else {\n                document.getLineNumber(start)\n            }\n            val textRange = TextRange(document.getLineStartOffset(lineNumber), document.getLineEndOffset(lineNumber))\n            return createTextRangeProblem(manager, textRange, isOnTheFly, psiFile, ruleName, desc)\n        }\n        if (psiFile.virtualFile.canonicalPath!!.endsWith(\".vm\")) {\n            return createTextRangeProblem(manager, TextRange(start, end), isOnTheFly, psiFile, ruleName, desc)\n        }\n        var psiElement = psiFile.findElementAt(start) ?: return null\n\n        psiElement = transform(psiElement) ?: return null\n        var endElement = if (start == end) psiElement else getEndElement(psiFile, psiElement, end)\n        if (psiElement != endElement && endElement.parent is PsiField) {\n            psiElement = endElement\n        }\n        if (endElement is PsiWhiteSpace) {\n            endElement = psiElement\n        }\n        if (psiElement is PsiWhiteSpace) {\n            val textRange = TextRange(start, end)\n            return createTextRangeProblem(manager, textRange, isOnTheFly, psiFile, ruleName, desc)\n        }\n\n        if (psiElement.textRange.startOffset >= endElement.textRange.endOffset) {\n            if (!(psiElement is PsiFile && endElement is PsiFile)) {\n                return null\n            }\n            endElement = psiElement\n        }\n        return manager.createProblemDescriptor(psiElement, endElement,\n                desc, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly,\n                quickFix(psiElement))\n    }\n\n    private fun getEndElement(psiFile: PsiFile, psiElement: PsiElement, endOffset: Int): PsiElement {\n        var endElement = psiFile.findElementAt(endOffset)\n        if (endElement is PsiJavaToken && endElement.tokenType === ElementType.SEMICOLON) {\n            endElement = psiFile.findElementAt(endOffset - 1)\n        }\n        if (endElement is PsiIdentifier) {\n            return endElement\n        }\n        if (psiElement is PsiIdentifier) {\n            return psiElement\n        }\n        if (endElement == null || endElement is PsiWhiteSpace\n                || psiElement.textRange.startOffset >= endElement.textRange.endOffset) {\n            endElement = psiElement\n        }\n        return endElement\n    }\n\n    private fun transform(element: PsiElement): PsiElement? {\n        var psiElement: PsiElement? = element\n        while (psiElement is PsiWhiteSpace) {\n            psiElement = psiElement.getNextSibling()\n        }\n        if (psiElement == null) {\n            return null\n        }\n        if (psiElement is PsiKeyword && psiElement.text != null && (ObjectConstants.CLASS_LITERAL == psiElement.text\n                || ObjectConstants.INTERFACE_LITERAL == psiElement.text\n                || ObjectConstants.ENUM_LITERAL == psiElement.text) && psiElement.parent is PsiClass) {\n            val parent = psiElement.parent as PsiClass\n            val identifier = parent.nameIdentifier\n            return identifier ?: psiElement\n        }\n        return psiElement\n    }\n\n    private fun createTextRangeProblem(manager: InspectionManager, textRange: TextRange, isOnTheFly: Boolean,\n            psiFile: PsiFile, ruleName: String, desc: String,\n            quickFix: () -> LocalQuickFix? = {\n                QuickFixes.getQuickFix(ruleName, isOnTheFly)\n            }): ProblemDescriptor {\n\n        return manager.createProblemDescriptor(psiFile, textRange,\n                desc, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,\n                isOnTheFly, quickFix())\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/QuickFixes.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.util\n\nimport com.alibaba.p3c.idea.quickfix.AvoidStartWithDollarAndUnderLineNamingQuickFix\nimport com.alibaba.p3c.idea.quickfix.ClassMustHaveAuthorQuickFix\nimport com.alibaba.p3c.idea.quickfix.ConstantFieldShouldBeUpperCaseQuickFix\nimport com.alibaba.p3c.idea.quickfix.LowerCamelCaseVariableNamingQuickFix\nimport com.alibaba.p3c.idea.quickfix.VmQuietReferenceQuickFix\nimport com.intellij.codeInspection.LocalQuickFix\n\n/**\n *\n *\n * @author caikang\n * @date 2017/02/06\n */\nobject QuickFixes {\n    val quickFixes = mutableMapOf(VmQuietReferenceQuickFix.ruleName to VmQuietReferenceQuickFix,\n            ClassMustHaveAuthorQuickFix.ruleName to ClassMustHaveAuthorQuickFix,\n            ConstantFieldShouldBeUpperCaseQuickFix.ruleName to ConstantFieldShouldBeUpperCaseQuickFix,\n            AvoidStartWithDollarAndUnderLineNamingQuickFix.ruleName to AvoidStartWithDollarAndUnderLineNamingQuickFix,\n            LowerCamelCaseVariableNamingQuickFix.ruleName to LowerCamelCaseVariableNamingQuickFix)\n\n    fun getQuickFix(rule: String, isOnTheFly: Boolean): LocalQuickFix? {\n        val quickFix = quickFixes[rule] ?: return null\n        if (!quickFix.onlyOnThFly) {\n            return quickFix\n        }\n        if (!isOnTheFly && quickFix.onlyOnThFly) {\n            return null\n        }\n        return quickFix\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/withLockNotInline.kt",
    "content": "package com.alibaba.p3c.idea.util\n\nimport com.intellij.openapi.progress.ProcessCanceledException\nimport java.util.concurrent.Semaphore\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.locks.Lock\n\n/**\n * @date 2020/06/14\n * @author caikang\n */\n\nfun <T> Lock.withLockNotInline(action: () -> T?): T? {\n    lock()\n    try {\n        return action()\n    } finally {\n        unlock()\n    }\n}\n\nfun <T> Semaphore.withAcquire(action: () -> T?): T? {\n    acquire()\n    try {\n        return action()\n    } finally {\n        release()\n    }\n}\n\nfun <T> Lock.withTryLock(time: Long, timeUnit: TimeUnit, action: () -> T?): T? {\n    if (!tryLock(time, timeUnit)) {\n        throw ProcessCanceledException()\n    }\n    try {\n        return action()\n    } finally {\n        unlock()\n    }\n}\n\nfun <T> Semaphore.withTryAcquire(time: Long, timeUnit: TimeUnit, action: () -> T?): T? {\n    if (!tryAcquire(time, timeUnit)) {\n        throw ProcessCanceledException()\n    }\n    try {\n        return action()\n    } finally {\n        release()\n    }\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/vcs/AliCodeAnalysisCheckinHandler.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.vcs\n\nimport com.alibaba.p3c.idea.action.AliInspectionAction\nimport com.alibaba.p3c.idea.compatible.inspection.Inspections\nimport com.alibaba.p3c.idea.config.P3cConfig\nimport com.alibaba.p3c.idea.inspection.AliBaseInspection\nimport com.alibaba.smartfox.idea.common.util.BalloonNotifications\nimport com.intellij.analysis.AnalysisScope\nimport com.intellij.codeInspection.InspectionManager\nimport com.intellij.codeInspection.LocalInspectionTool\nimport com.intellij.codeInspection.ex.InspectionManagerEx\nimport com.intellij.openapi.application.ApplicationManager\nimport com.intellij.openapi.components.ServiceManager\nimport com.intellij.openapi.diagnostic.Logger\nimport com.intellij.openapi.progress.ProcessCanceledException\nimport com.intellij.openapi.progress.ProgressIndicator\nimport com.intellij.openapi.progress.ProgressManager\nimport com.intellij.openapi.progress.Task\nimport com.intellij.openapi.project.DumbService\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.ui.Messages\nimport com.intellij.openapi.util.Computable\nimport com.intellij.openapi.util.Ref\nimport com.intellij.openapi.vcs.CheckinProjectPanel\nimport com.intellij.openapi.vcs.VcsBundle\nimport com.intellij.openapi.vcs.changes.CommitExecutor\nimport com.intellij.openapi.vcs.checkin.CheckinHandler\nimport com.intellij.openapi.vcs.checkin.CheckinHandlerUtil\nimport com.intellij.openapi.vcs.ui.RefreshableOnComponent\nimport com.intellij.openapi.vfs.VirtualFile\nimport com.intellij.psi.PsiDocumentManager\nimport com.intellij.psi.PsiManager\nimport com.intellij.ui.NonFocusableCheckBox\nimport com.intellij.util.ExceptionUtil\nimport com.intellij.util.PairConsumer\nimport java.awt.BorderLayout\nimport java.util.ArrayList\nimport java.util.Arrays\nimport java.util.concurrent.atomic.AtomicBoolean\nimport java.util.concurrent.atomic.AtomicInteger\nimport javax.swing.JComponent\nimport javax.swing.JPanel\n\n/**\n *\n * @author yaohui.wyh\n * @date 2017/03/21\n * @author caikang\n * @date 2017/05/04\n */\nclass AliCodeAnalysisCheckinHandler(\n    private val myProject: Project,\n    private val myCheckinPanel: CheckinProjectPanel\n) : CheckinHandler() {\n    private val dialogTitle = \"Alibaba Code Analyze\"\n    private val cancelText = \"&Cancel\"\n    private val commitText = \"&Commit Anyway\"\n    private val waitingText = \"Wait\"\n\n    val log = Logger.getInstance(javaClass)\n\n    override fun getBeforeCheckinConfigurationPanel(): RefreshableOnComponent? {\n        val checkBox = NonFocusableCheckBox(\"Alibaba Code Guidelines\")\n        return object : RefreshableOnComponent {\n            override fun getComponent(): JComponent {\n                val panel = JPanel(BorderLayout())\n                panel.add(checkBox)\n                val dumb = DumbService.isDumb(myProject)\n                checkBox.isEnabled = !dumb\n                checkBox.toolTipText = if (dumb) {\n                    \"Code analysis is impossible until indices are up-to-date\"\n                } else {\n                    \"\"\n                }\n                return panel\n            }\n\n            override fun refresh() {}\n\n            override fun saveState() {\n                getSettings().analysisBeforeCheckin = checkBox.isSelected\n            }\n\n            override fun restoreState() {\n                checkBox.isSelected = getSettings().analysisBeforeCheckin\n            }\n        }\n    }\n\n    private fun getSettings(): P3cConfig {\n        return ServiceManager.getService(P3cConfig::class.java)\n    }\n\n    override fun beforeCheckin(\n        executor: CommitExecutor?,\n        additionalDataConsumer: PairConsumer<Any, Any>\n    ): CheckinHandler.ReturnResult {\n        if (!getSettings().analysisBeforeCheckin) {\n            return CheckinHandler.ReturnResult.COMMIT\n        }\n        if (DumbService.getInstance(myProject).isDumb) {\n            if (Messages.showOkCancelDialog(\n                    myProject,\n                    \"Code analysis is impossible until indices are up-to-date\", dialogTitle,\n                    waitingText, commitText, null\n                ) == Messages.OK\n            ) {\n                return CheckinHandler.ReturnResult.CANCEL\n            }\n            return CheckinHandler.ReturnResult.COMMIT\n        }\n\n        val virtualFiles = CheckinHandlerUtil.filterOutGeneratedAndExcludedFiles(myCheckinPanel.virtualFiles, myProject)\n        val hasViolation = hasViolation(virtualFiles, myProject)\n        if (!hasViolation) {\n            BalloonNotifications.showSuccessNotification(\n                \"No suspicious code found！\",\n                myProject, \"Analyze Finished\"\n            )\n            return CheckinHandler.ReturnResult.COMMIT\n        }\n        if (Messages.showOkCancelDialog(\n                myProject, \"Found suspicious code,continue commit？\",\n                dialogTitle, commitText, cancelText, null\n            ) == Messages.OK\n        ) {\n            return CheckinHandler.ReturnResult.COMMIT\n        } else {\n            doAnalysis(myProject, virtualFiles.toTypedArray())\n            return CheckinHandler.ReturnResult.CLOSE_WINDOW\n        }\n    }\n\n    fun doAnalysis(project: Project, virtualFiles: Array<VirtualFile>) {\n        val managerEx = InspectionManager.getInstance(project) as InspectionManagerEx\n        val analysisScope = AnalysisScope(\n            project,\n            ArrayList(Arrays.asList(*virtualFiles))\n        )\n        val tools = Inspections.aliInspections(project) { it.tool is AliBaseInspection }\n        AliInspectionAction.createContext(tools, managerEx, null, false, analysisScope)\n            .doInspections(analysisScope)\n    }\n\n    private fun hasViolation(virtualFiles: List<VirtualFile>, project: Project): Boolean {\n        ApplicationManager.getApplication().assertIsDispatchThread()\n        PsiDocumentManager.getInstance(myProject).commitAllDocuments()\n        if (ApplicationManager.getApplication().isWriteAccessAllowed) throw RuntimeException(\n            \"Must not run under write action\"\n        )\n        val result = AtomicBoolean(false)\n        val exception = Ref.create<Exception>()\n        ProgressManager.getInstance().run(\n            object : Task.Modal(myProject, VcsBundle.message(\"checking.code.smells.progress.title\"), true) {\n                override fun run(progress: ProgressIndicator) {\n                    try {\n                        val tools = Inspections.aliInspections(project) { it.tool is AliBaseInspection }\n                        val inspectionManager = InspectionManager.getInstance(project)\n                        val psiManager = PsiManager.getInstance(project)\n                        val count = AtomicInteger(0)\n                        val hasViolation = virtualFiles.asSequence().any { file ->\n                            ApplicationManager.getApplication().runReadAction(Computable {\n                                val psiFile = psiManager.findFile(file) ?: return@Computable false\n                                val curCount = count.incrementAndGet()\n                                progress.text = file.canonicalPath\n                                progress.fraction = curCount.toDouble() / virtualFiles.size.toDouble()\n                                return@Computable tools.any {\n                                    progress.checkCanceled()\n                                    val tool = it.tool as LocalInspectionTool\n                                    val aliTool = tool as AliBaseInspection\n                                    progress.text2 = aliTool.ruleName()\n                                    val problems = tool.processFile(psiFile, inspectionManager)\n                                    problems.size > 0\n                                }\n                            })\n\n                        }\n                        result.set(hasViolation)\n                    } catch (e: ProcessCanceledException) {\n                        result.set(false)\n                    } catch (e: Exception) {\n                        log.error(e)\n                        exception.set(e)\n                    }\n                }\n            })\n        if (!exception.isNull) {\n            val t = exception.get()\n            ExceptionUtil.rethrowAllAsUnchecked(t)\n        }\n\n        return result.get()\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/vcs/AliCodeAnalysisCheckinHandlerFactory.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.idea.vcs\n\nimport com.intellij.openapi.vcs.CheckinProjectPanel\nimport com.intellij.openapi.vcs.changes.CommitContext\nimport com.intellij.openapi.vcs.checkin.CheckinHandler\nimport com.intellij.openapi.vcs.checkin.CheckinHandlerFactory\n\n/**\n *\n *\n * @author caikang\n * @date 2017/05/04\n */\nclass AliCodeAnalysisCheckinHandlerFactory : CheckinHandlerFactory() {\n    override fun createHandler(panel: CheckinProjectPanel, commitContext: CommitContext): CheckinHandler {\n        return AliCodeAnalysisCheckinHandler(panel.project, panel)\n    }\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/component/AliBaseApplicationComponent.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.idea.common.component\n\nimport com.alibaba.smartfox.idea.common.util.PluginVersions\nimport com.intellij.openapi.components.ApplicationComponent\n\n/**\n *\n *\n * @author caikang\n * @date 2017/05/11\n */\ninterface AliBaseApplicationComponent : ApplicationComponent {\n    override fun getComponentName(): String {\n        return \"${PluginVersions.pluginId.idString}-${javaClass.name}\"\n    }\n\n    override fun disposeComponent() {\n    }\n\n    override fun initComponent() {\n    }\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/component/AliBaseProjectComponent.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.idea.common.component\n\nimport com.alibaba.smartfox.idea.common.util.PluginVersions\nimport com.intellij.openapi.components.ProjectComponent\n\n/**\n *\n *\n * @author caikang\n * @date 2017/04/28\n */\ninterface AliBaseProjectComponent : ProjectComponent {\n    override fun getComponentName(): String {\n        return \"${PluginVersions.pluginId.idString}-${javaClass.name}\"\n    }\n\n    override fun disposeComponent() {\n    }\n\n    override fun projectClosed() {\n    }\n\n    override fun initComponent() {\n    }\n\n    override fun projectOpened() {\n    }\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/util/BalloonNotifications.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.idea.common.util\n\nimport com.intellij.notification.NotificationDisplayType\nimport com.intellij.notification.NotificationGroup\nimport com.intellij.notification.NotificationListener\nimport com.intellij.notification.NotificationType\nimport com.intellij.openapi.progress.ProcessCanceledException\nimport com.intellij.openapi.project.Project\nimport com.intellij.openapi.project.ProjectManager\nimport com.intellij.openapi.ui.Messages\nimport java.awt.Component\nimport java.net.UnknownHostException\n\n/**\n *\n *\n * @author caikang\n * @date 2017/05/08\n */\nobject BalloonNotifications {\n    val displayId = \"SmartFox Intellij IDEA Balloon Notification\"\n    val balloonGroup = NotificationGroup(displayId, NotificationDisplayType.BALLOON, true)\n\n    val stickyBalloonDisplayId = \"SmartFox Intellij IDEA Notification\"\n    val stickyBalloonGroup = NotificationGroup(stickyBalloonDisplayId, NotificationDisplayType.STICKY_BALLOON, true)\n    val TITLE = \"SmartFox Intellij IDEA Plugin\"\n\n    fun showInfoDialog(component: Component, title: String, message: String) {\n        Messages.showInfoMessage(component, message, title)\n    }\n\n    fun showErrorDialog(component: Component, title: String, errorMessage: String) {\n        Messages.showErrorDialog(component, errorMessage, title)\n    }\n\n    fun showErrorDialog(component: Component, title: String, e: Exception) {\n        if (isOperationCanceled(e)) {\n            return\n        }\n        Messages.showErrorDialog(component, getErrorTextFromException(e), title)\n    }\n\n    fun showSuccessNotification(message: String, project: Project? = ProjectManager.getInstance().defaultProject,\n            title: String = TITLE, sticky: Boolean = false) {\n        showNotification(message, project, title, NotificationType.INFORMATION, null, sticky)\n    }\n\n    fun showWarnNotification(message: String, project: Project? = ProjectManager.getInstance().defaultProject,\n            title: String = TITLE, sticky: Boolean = false) {\n        showNotification(message, project, title, NotificationType.WARNING, null, sticky)\n    }\n\n    fun showErrorNotification(message: String, project: Project? = ProjectManager.getInstance().defaultProject,\n            title: String = TITLE, sticky: Boolean = false) {\n        showNotification(message, project, title, NotificationType.ERROR, null, sticky)\n    }\n\n    fun showSuccessNotification(message: String, project: Project?,\n            notificationListener: NotificationListener, title: String = TITLE, sticky: Boolean = false) {\n        showNotification(message, project, title, NotificationType.INFORMATION, notificationListener, sticky)\n    }\n\n    fun showNotification(message: String, project: Project? = ProjectManager.getInstance().defaultProject,\n            title: String = TITLE,\n            notificationType: NotificationType = NotificationType.INFORMATION,\n            notificationListener: NotificationListener? = null, sticky: Boolean = false) {\n        val group = if (sticky) {\n            stickyBalloonGroup\n        } else {\n            balloonGroup\n        }\n        group.createNotification(title, message, notificationType, notificationListener).notify(project)\n    }\n\n    private fun isOperationCanceled(e: Exception): Boolean {\n        return e is ProcessCanceledException\n    }\n\n    fun getErrorTextFromException(e: Exception): String {\n        if (e is UnknownHostException) {\n            return \"Unknown host: \" + e.message\n        }\n        return e.message ?: \"\"\n    }\n}\n\nobject LogNotifications {\n    val group = NotificationGroup(BalloonNotifications.displayId, NotificationDisplayType.NONE, true)\n\n    fun log(message: String, project: Project? = ProjectManager.getInstance().defaultProject,\n            title: String = BalloonNotifications.TITLE,\n            notificationType: NotificationType = NotificationType.INFORMATION,\n            notificationListener: NotificationListener? = null) {\n        group.createNotification(title, message, notificationType, notificationListener).notify(project)\n    }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/util/CommonExtensions.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.idea.common.util\n\nimport com.intellij.openapi.components.ServiceManager\nimport com.intellij.openapi.project.Project\n\n/**\n *\n *\n * @author caikang\n * @date 2017/06/19\n */\nfun <T> Class<T>.getService(): T {\n    return ServiceManager.getService(this)\n}\n\nfun <T> Class<T>.getService(project: Project): T {\n    return ServiceManager.getService(project, this)\n}"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/util/PluginVersions.kt",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.smartfox.idea.common.util\n\nimport com.intellij.ide.plugins.IdeaPluginDescriptor\nimport com.intellij.ide.plugins.PluginManager\nimport com.intellij.ide.plugins.cl.PluginClassLoader\nimport com.intellij.openapi.application.ApplicationInfo\nimport com.intellij.openapi.extensions.PluginId\n\n/**\n * @author caikang\n */\nobject PluginVersions {\n    val baseVersion141 = 141\n    val baseVersion143 = 143\n    val baseVersion145 = 145\n    val baseVersion162 = 162\n    val baseVersion163 = 163\n    val baseVersion171 = 171\n\n    val pluginId: PluginId = (javaClass.classLoader as PluginClassLoader).pluginId\n    val pluginDescriptor: IdeaPluginDescriptor = PluginManager.getPlugin(pluginId)!!\n\n    /**\n     * 获取当前安装的 plugin版本\n     */\n    val pluginVersion: String\n        get() = pluginDescriptor.version\n\n    /**\n     * 获取当前使用的IDE版本\n     */\n    val ideVersion: String\n        get() {\n            val applicationInfo = ApplicationInfo.getInstance()\n            return applicationInfo.fullVersion + \"_\" + applicationInfo.build\n        }\n\n\n    val baseVersion: Int\n        get() {\n            val applicationInfo = ApplicationInfo.getInstance()\n            return applicationInfo.build.baselineVersion\n        }\n}\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/resources/messages/P3cBundle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n<properties>\n    <entry key=\"com.alibaba.p3c.analytics.action_group.text\">阿里编码规约</entry>\n    <entry key=\"com.alibaba.p3c.action.switch_language.text.cur_zh\">切换语言至英文(English)</entry>\n    <entry key=\"com.alibaba.p3c.action.switch_language.text.cur_en\">切换语言至中文</entry>\n    <entry key=\"com.alibaba.p3c.action.switch_language.text.success\">\n        <![CDATA[切换语言成功，<a href=\"restart\">重启</a>后生效]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.action.AliInspectionAction.text\">编码规约扫描</entry>\n    <entry key=\"com.alibaba.p3c.idea.action.ToggleProjectInspectionAction.text.close\">关闭实时检测功能</entry>\n    <entry key=\"com.alibaba.p3c.idea.action.ToggleProjectInspectionAction.text.open\">打开实时检测功能</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.delete_$\">删除开头的 $ 或者 _</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.generate.author\">添加/提取 @author</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.field.to.upperCaseWithUnderscore\">修正为以下划线分隔大写模式</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.variable.lowerCamelCase\">修改为小写驼峰命名（lowerCamelCase）</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.vm.add!\">为变量添加!</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.replace.with\">替换为</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.standalone.AliAccessStaticViaInstanceInspection\">通过类 '%s' 直接访问静态成员\n        '%s.%s'\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.standalone.AliMissingOverrideAnnotationInspection\">添加 @Override 注解</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.NeedBraceRule\">为语句加上大括号</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.AliEqualsAvoidNull\">翻转 equals 调用</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.ArrayNamingShouldHaveBracketRule\">修改为 String[] str 模式</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.AliLongLiteralsEndingWithLowercaseL\">'l' 替换为 'L'</entry>\n\n    <entry key=\"com.alibaba.p3c.idea.inspection.equals.instead.quality\">\n        <![CDATA[包装类型间的相等判断应该用equals，而不是<code>#ref</code> #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection.message\">\n        避免通过一个类的对象引用访问此类的静态变量或静态方法，无谓增加编译器解析成本，直接用类名来访问即可。\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection.errMsg\">不应该通过类实例访问静态成员\n        %s #loc\n    </entry>\n\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliDeprecationInspection.message\">不能使用过时的类或方法。</entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection.message\">\n        所有的覆写方法，必须加@Override注解。\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection.errMsg\">\n        <![CDATA[<code>#ref()</code>缺少 '@Override' 注解 #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection.message\">\n        Map/Set的key为自定义对象时，必须重写hashCode和equals。\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection.errMsg\">\n        参数类型 %s 没有重写hashCode和equals #loc\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.AvoidCallStaticSimpleDateFormatRule.errMsg\">\n        <![CDATA[<code>#ref</code> 是非线程安全的，请加锁或者使用局部变量 #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.NeedBraceRule.errMsg\">\n        <![CDATA[<code>#ref</code> 没有加大括号 #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.AliEqualsAvoidNull.errMsg\">\n        <![CDATA[<code>#ref</code> 应该作为方法 \"%s()\"的调用方，而不是参数 #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.ArrayNamingShouldHaveBracketRule.errMsg\">\n        <![CDATA[{0, choice, 1#字段|2#参数|3#变量} <code>#ref</code> 数组定义格式错误 #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.AliLongLiteralsEndingWithLowercaseL.errMsg\">\n        <![CDATA['long' 型常量 <code>#ref</code> 应该以大写L结尾 #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.WrapperTypeEqualityRule.errMsg\">\n        <![CDATA[包装类型间的相等判断应该用equals，而不是<code>#ref</code> #loc]]></entry>\n\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection.desc\"><![CDATA[\n<html>\n<body>\n避免通过一个类的对象引用访问此类的静态变量或静态方法，无谓增加编译器解析成本，直接用类名来访问即可。\n</body>\n</html>\n]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliDeprecationInspection.desc\"><![CDATA[\n<html>\n<body>\n不能使用过时的类或方法。<br>\n说明：java.net.URLDecoder 中的方法decode(String encodeStr) 这个方法已经过时，应该使用双参数decode(String source, String encode)。接口提供方既然明确是过时接口，那么有义务同时提供新的接口；作为调用方来说，有义务去考证过时方法的新实现是什么。\n</body>\n</html>\n]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection.desc\"><![CDATA[\n<html>\n<body>\n所有的覆写方法，必须加@Override注解。<br>\n反例：getObject()与get0bject()的问题。一个是字母的O，一个是数字的0，加@Override可以准确判断是否覆盖成功。另外，如果在抽象类中对方法签名进行修改，其实现类会马上编译报错。\n</body>\n</html>\n]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection.desc\">\n        <![CDATA[\n<html>\n<body>\nMap/Set的key为自定义对象时，必须重写hashCode和equals。<br>\n关于hashCode和equals的处理，遵循如下规则：<br/>\n 1） 只要重写equals，就必须重写hashCode。<br/>\n 2） 因为Set存储的是不重复的对象，依据hashCode和equals进行判断，所以Set存储的对象必须重写这两个方法。<br/>\n 3） 如果自定义对象做为Map的键，那么必须重写hashCode和equals。<br/>\n</body>\n</html>\n]]></entry>\n</properties>\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/resources/messages/P3cBundle_en.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n<properties>\n    <entry key=\"com.alibaba.p3c.analytics.action_group.text\">Alibaba Coding Guidelines</entry>\n    <entry key=\"com.alibaba.p3c.action.switch_language.text.cur_zh\">Switch language to English</entry>\n    <entry key=\"com.alibaba.p3c.action.switch_language.text.cur_en\">Switch language to Chinese</entry>\n    <entry key=\"com.alibaba.p3c.action.switch_language.text.success\">\n        <![CDATA[Switch language success，<a href=\"restart\">restart</a> to get effect.]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.action.AliInspectionAction.text\">Alibaba Coding Guidelines Analyze</entry>\n    <entry key=\"com.alibaba.p3c.idea.action.ToggleProjectInspectionAction.text.close\">Close inspection on the fly\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.action.ToggleProjectInspectionAction.text.open\">Open inspection on the fly</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.delete_$\">Delete starting '$' or '_'</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.generate.author\">Add/Extract @author</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.field.to.upperCaseWithUnderscore\">Refactor to upper case with underscore\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.variable.lowerCamelCase\">Refactor to lower camel case name</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.vm.add!\">Add '!' for variable</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.replace.with\">Replace with</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.standalone.AliAccessStaticViaInstanceInspection\">Access static '%s.%s' via\n        class '%s' reference.\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.standalone.AliMissingOverrideAnnotationInspection\">Add @Override\n        annotation\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.NeedBraceRule\">Add braces to statement</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.AliEqualsAvoidNull\">Flip 'equals()'</entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.ArrayNamingShouldHaveBracketRule\">Replace with Java-style array\n        declaration\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.quickfix.AliLongLiteralsEndingWithLowercaseL\">Replace 'l' with 'L'</entry>\n\n    <entry key=\"com.alibaba.p3c.idea.inspection.equals.instead.quality\">\n        <![CDATA[<code>#ref</code> should replace with equals for wrapper type #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection.message\">A static field\n        or method should be directly referred by its class name instead of its corresponding object name.\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection.errMsg\">%s access static\n        member via class instance is prohibited #loc\n    </entry>\n\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliDeprecationInspection.message\">Using a deprecated class or\n        method is prohibited.\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection.message\">An overridden\n        method from an interface or abstract class must be marked with @Override annotation.\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection.errMsg\">\n        <![CDATA[Missing '@Override' annotation on <code>#ref()</code> #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection.message\">\n        Custom class must override 'hashCode' and 'equals' while use as key for Map or value for Set.\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection.errMsg\">\n        Type of parameter %s does not override 'hashCode' and 'equals' #loc\n    </entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.AvoidCallStaticSimpleDateFormatRule.errMsg\">\n        <![CDATA[<code>#ref</code> is unsafe,lock or use local variable #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.NeedBraceRule.errMsg\">\n        <![CDATA[<code>#ref</code> without braces #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.AliEqualsAvoidNull.errMsg\">\n        <![CDATA[<code>#ref</code> is argument of '%s()', instead of its target #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.AliLongLiteralsEndingWithLowercaseL.errMsg\">\n        <![CDATA['long' literal <code>#ref</code> ends with lowercase 'l' #loc]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.WrapperTypeEqualityRule.errMsg\">\n        <![CDATA[The wrapper classes should be compared by equals method rather than by symbol of '==' directly #loc]]></entry>\n\n    <entry key=\"com.alibaba.p3c.idea.inspection.rule.ArrayNamingShouldHaveBracketRule.errMsg\">\n        <![CDATA[C-style array declaration of {0, choice, 1#field|2#parameter|3#local variable} <code>#ref</code> #loc]]></entry>\n\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection.desc\"><![CDATA[\n<html>\n<body>\nA static field or method should be directly referred by its class name instead of its corresponding object name.\n</body>\n</html>\n]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliDeprecationInspection.desc\"><![CDATA[\n<html>\n<body>\nUsing a deprecated class or method is prohibited.<br>\nNote: For example, decode(String source, String encode) should be used instead of the deprecated method decode(String encodeStr). Once an interface has been deprecated, the interface provider has the obligation to provide a new one. At the same time, client programmers have the obligation to check out what its new implementation is.\n</body>\n</html>\n]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection.desc\"><![CDATA[\n<html>\n<body>\nAn overridden method from an interface or abstract class must be marked with @Override annotation.<br>\nCounter example: For getObject() and get0bject(), the first one has a letter 'O', and the second one has a number '0'. To accurately determine whether the overriding is successful, an @Override annotation is necessary. Meanwhile, once the method signature in the abstract class is changed, the implementation class will report a compile-time error immediately.\n</body>\n</html>\n]]></entry>\n    <entry key=\"com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection.desc\">\n        <![CDATA[\n<html>\n<body>\nCustom class must override 'hashCode' and 'equals' while use as key for Map or value for Set.<br>\nThe usage of hashCode and equals should follow:<br/>\n 1) Override hashCode if equals is overridden.<br/>\n 2) These two methods must be overridden for Set since they are used to ensure that no duplicate object will be inserted in Set.<br/>\n 3) These two methods must be overridden if self-defined object is used as the key of Map.<br/>\nNote: String can be used as the key of Map since these two methods have been rewritten.\n</body>\n</html>\n]]></entry>\n</properties>\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/resources/rulesets/java/ali-pmd.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" name=\"alibaba-pmd\"\n         xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n\n    <rule ref=\"rulesets/java/ali-concurrent.xml\"/>\n    <rule ref=\"rulesets/java/ali-comment.xml\"/>\n    <rule ref=\"rulesets/java/ali-naming.xml\">\n        <exclude name=\"ArrayNamingShouldHaveBracketRule\"/>\n    </rule>\n    <rule ref=\"rulesets/java/ali-constant.xml\">\n        <exclude name=\"UpperEllRule\"/>\n    </rule>\n    <rule ref=\"rulesets/java/ali-other.xml\"/>\n    <rule ref=\"rulesets/java/ali-orm.xml\"/>\n    <rule ref=\"rulesets/java/ali-exception.xml\"/>\n    <rule ref=\"rulesets/java/ali-oop.xml\">\n        <exclude name=\"EqualsAvoidNullRule\"/>\n        <exclude name=\"WrapperTypeEqualityRule\"/>\n    </rule>\n    <rule ref=\"rulesets/java/ali-set.xml\"/>\n    <rule ref=\"rulesets/java/ali-flowcontrol.xml\">\n        <exclude name=\"NeedBraceRule\"/>\n    </rule>\n</ruleset>\n"
  },
  {
    "path": "idea-plugin/p3c-common/src/main/resources/tpl/StaticDescriptionTemplate.ftl",
    "content": "<#ftl output_format=\"HTML\">\n<html>\n<body>\n<span style=\"color:orange\">\n    <pre>${message}<#if description??><br>${description}</#if></pre>\n</span>\n<#list examples as example>\n<pre>${example}</pre>\n</#list>\n<!-- tooltip end -->\n</body>\n</html>\n"
  },
  {
    "path": "idea-plugin/p3c-idea/build.gradle",
    "content": "plugins {\n    id \"org.jetbrains.intellij\" version '0.4.5'\n}\napply plugin: 'kotlin'\napply plugin: 'idea'\n\ndef myPlugins = ['git4idea']\ndef versionDotIndex = idea_version.indexOf('.')\ndef intVersion = versionDotIndex == -1 ? Integer.parseInt(idea_version) : Integer.parseInt(idea_version.substring(0, versionDotIndex))\nif (intVersion >= 2019 || (intVersion < 1000 && intVersion >= 193)) {\n    myPlugins = ['git4idea', 'java']\n}\n\nintellij {\n    version idea_version\n    plugins = myPlugins\n    pluginName plugin_name\n    updateSinceUntilBuild false\n    sandboxDirectory \"idea-sandbox\"\n}\n\nversion plugin_version\n\ndependencies {\n    compile group: 'org.freemarker', name: 'freemarker', version: '2.3.25-incubating'\n    compile project(':p3c-common')\n    compile group: 'org.javassist', name: 'javassist', version: '3.21.0-GA'\n}\n\n"
  },
  {
    "path": "idea-plugin/p3c-idea/src/main/resources/META-INF/p3c.xml",
    "content": "<idea-plugin>\n    <application-components>\n        <component>\n            <implementation-class>com.alibaba.p3c.idea.component.CommonSettingsApplicationComponent</implementation-class>\n        </component>\n    </application-components>\n    <project-components>\n        <component>\n            <implementation-class>com.alibaba.p3c.idea.component.AliProjectComponent</implementation-class>\n        </component>\n    </project-components>\n    <actions>\n        <action class=\"com.alibaba.p3c.idea.action.AliInspectionAction\" id=\"AliP3CInspectionAction\"\n                popup=\"true\" text=\"编码规约扫描\" icon=\"P3cIcons.ANALYSIS_ACTION\">\n            <keyboard-shortcut keymap=\"$default\"\n                               first-keystroke=\"shift ctrl alt J\"/>\n            <add-to-group group-id=\"MainToolBar\" anchor=\"last\"/>\n            <add-to-group group-id=\"ProjectViewPopupMenu\" anchor=\"last\"/>\n            <add-to-group group-id=\"ChangesViewPopupMenu\" anchor=\"last\"/>\n            <add-to-group group-id=\"EditorPopupMenu\" anchor=\"last\"/>\n        </action>\n        <action class=\"com.alibaba.p3c.idea.action.ToggleProjectInspectionAction\" id=\"ToggleProjectInspectionAction\"\n                popup=\"true\" text=\"关闭检测\" icon=\"P3cIcons.PROJECT_INSPECTION_OFF\">\n            <add-to-group group-id=\"MainToolBar\" anchor=\"last\"/>\n            <add-to-group group-id=\"ProjectViewPopupMenu\" anchor=\"last\"/>\n            <add-to-group group-id=\"ChangesViewPopupMenu\" anchor=\"last\"/>\n            <add-to-group group-id=\"EditorPopupMenu\" anchor=\"last\"/>\n        </action>\n        <action class=\"com.alibaba.p3c.idea.action.SwitchLanguageAction\"\n                id=\"com.alibaba.p3c.idea.action.SwitchLanguageAction\"\n                icon=\"P3cIcons.LANGUAGE\">\n        </action>\n        <group popup=\"true\" id=\"com.alibaba.p3c.analytics.action_group\" text=\"编码规约\" icon=\"P3cIcons.ALIBABA\">\n            <reference ref=\"AliP3CInspectionAction\"/>\n            <reference ref=\"ToggleProjectInspectionAction\"/>\n            <reference ref=\"com.alibaba.p3c.idea.action.SwitchLanguageAction\"/>\n            <add-to-group group-id=\"ToolsMenu\" anchor=\"last\"/>\n        </group>\n    </actions>\n\n    <extensionPoints>\n        <extensionPoint name=\"inspectionAction\"\n                        interface=\"com.alibaba.p3c.idea.ep.InspectionActionExtensionPoint\"/>\n    </extensionPoints>\n    <extensions defaultExtensionNs=\"com.intellij\">\n        <applicationService serviceImplementation=\"com.alibaba.p3c.idea.config.P3cConfig\"/>\n        <projectService serviceImplementation=\"com.alibaba.p3c.idea.config.SmartFoxProjectConfig\"/>\n        <checkinHandlerFactory implementation=\"com.alibaba.p3c.idea.vcs.AliCodeAnalysisCheckinHandlerFactory\"\n                               order=\"first\"/>\n        <inspectionToolProvider implementation=\"com.alibaba.p3c.idea.inspection.AliLocalInspectionToolProvider\"/>\n    </extensions>\n</idea-plugin>\n"
  },
  {
    "path": "idea-plugin/p3c-idea/src/main/resources/META-INF/plugin.xml",
    "content": "<idea-plugin>\n    <id>com.alibaba.p3c.smartfox</id>\n    <name>Alibaba Java Coding Guidelines</name>\n    <description>Alibaba Java Coding Guidelines plugin support.</description>\n\n    <change-notes>\n        <![CDATA[\n         <ul>\n        2.1.0\n        <li>Fix idea 2020.2 Ultimate compatibility issue</li>\n        <li>Minimum supported idea version up to 2018.3</li>\n        <li>Kotlin upgrade to 1.3.72</li>\n        <li>Disable real time inspect if file lines more than 3000 lines</li>\n        <li>Fix https://github.com/alibaba/p3c/issues/722</li>\n        <li>Fix https://github.com/alibaba/p3c/issues/620</li>\n        </ul>\n        <ul>\n        2.0.2\n        <li>Fix idea 2020.1 Ultimate compatibility issue</li>\n        </ul>\n        <ul>\n        2.0.1\n        <li>Fix idea 2019.3 compatibility issue</li>\n        <li>fix https://github.com/alibaba/p3c/issues/540</li>\n        <li>fix https://github.com/alibaba/p3c/issues/209</li>\n        <li>fix https://github.com/alibaba/p3c/issues/579</li>\n        <li>Add code style rule of lock</li>\n        </ul>\n        <ul>\n        2.0.0\n        <li>supported min idea version 2016.1(145.258.11)</li>\n        <li>supported min jdk version 1.8</li>\n        <li>fix persistent compatibility issue</li>\n        <li>fix https://github.com/alibaba/p3c/issues/430</li>\n        <li>fix https://github.com/alibaba/p3c/issues/454</li>\n        <li>fix https://github.com/alibaba/p3c/issues/409</li>\n        <li>add rule To judge the equivalence of floating-point numbers.</li>\n        <li>add annotation process for rule ClassMustHaveAuthorRule</li>\n        </ul>\n        <ul>1.0.6\n            <li>fix <a href=\"https://github.com/alibaba/p3c/issues/337\">https://github.com/alibaba/p3c/issues/337</a>  do not check annotation </li>\n            <li>PojoMustOverrideToStringRule do not check interface </li>\n            <li>Performance improvement</li>\n        </ul>\n          <ul>\n        1.0.5\n        <li>\n        Add rule [Recommended] The total number of lines for a method should not be more than 80.\n        </li>\n        <li>\n        Add rule [Recommended] Avoid using the negation operator '!'.\n        </li>\n        <li>\n        Add rule [Mandatory] When doing date formatting, \"y\" should be written in lowercase for \"year\" in a pattern statement\n        </li>\n         <li>https://github.com/alibaba/p3c/issues/264</li>\n         </ul>\n          <ul>\n        1.0.4\n         <li>fix https://github.com/alibaba/p3c/issues/217</li>\n        <li>fix https://github.com/alibaba/p3c/issues/208</li>\n        <li>fix https://github.com/alibaba/p3c/issues/195</li>\n        </ul>\n         <ul>\n        1.0.3\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/191\">https://github.com/alibaba/p3c/issues/191</a></li>\n        </ul>\n         <ul>\n        1.0.2\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/185\">https://github.com/alibaba/p3c/issues/185</a></li>\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/189\">https://github.com/alibaba/p3c/issues/189</a></li>\n        </ul>\n         <ul>\n        1.0.1\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/149\">https://github.com/alibaba/p3c/issues/149</a></li>\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/60\">https://github.com/alibaba/p3c/issues/60</a></li>\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/58\">https://github.com/alibaba/p3c/issues/58</a></li>\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/68\">https://github.com/alibaba/p3c/issues/68</a></li>\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/68\">https://github.com/alibaba/p3c/issues/68</a></li>\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/112\">https://github.com/alibaba/p3c/issues/112</a></li>\n        <li>fix <a href=\"https://github.com/alibaba/p3c/issues/127\">https://github.com/alibaba/p3c/issues/127</a></li>\n        </ul>\n        ]]>\n    </change-notes>\n    <vendor>alibaba</vendor>\n    <version>2.0.0</version>\n    <idea-version since-build=\"183.4284\"/>\n    <depends optional=\"true\">com.intellij.velocity</depends>\n    <depends optional=\"true\" config-file=\"p3c.xml\">com.intellij.modules.java</depends>\n    <depends>com.intellij.modules.platform</depends>\n    <depends>com.intellij.modules.lang</depends>\n    <depends>com.intellij.modules.vcs</depends>\n    <depends>com.intellij.modules.xml</depends>\n    <depends>com.intellij.modules.xdebugger</depends>\n</idea-plugin>\n"
  },
  {
    "path": "idea-plugin/settings.gradle",
    "content": "include 'p3c-idea'\ninclude 'p3c-common'\n"
  },
  {
    "path": "license.txt",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n    \"License\" shall mean the terms and conditions for use, reproduction, and\n    distribution as defined by Sections 1 through 9 of this document.\n\n    \"Licensor\" shall mean the copyright owner or entity authorized by the\n    copyright owner that is granting the License.\n\n    \"Legal Entity\" shall mean the union of the acting entity and all other\n    entities that control, are controlled by, or are under common control with\n    that entity. For the purposes of this definition, \"control\" means (i) the\n    power, direct or indirect, to cause the direction or management of such\n    entity, whether by contract or otherwise, or (ii) ownership of\n    fifty percent (50%) or more of the outstanding shares, or (iii) beneficial\n    ownership of such entity.\n\n    \"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\n    permissions granted by this License.\n\n    \"Source\" form shall mean the preferred form for making modifications,\n    including but not limited to software source code, documentation source,\n    and configuration files.\n\n    \"Object\" form shall mean any form resulting from mechanical transformation\n    or translation of a Source form, including but not limited to compiled\n    object code, generated documentation, and conversions to\n    other media types.\n\n    \"Work\" shall mean the work of authorship, whether in Source or Object\n    form, made available under the License, as indicated by a copyright notice\n    that is included in or attached to the work (an example is provided in the\n    Appendix below).\n\n    \"Derivative Works\" shall mean any work, whether in Source or Object form,\n    that is based on (or derived from) the Work and for which the editorial\n    revisions, annotations, elaborations, or other modifications represent,\n    as a whole, an original work of authorship. For the purposes of this\n    License, Derivative Works shall not include works that remain separable\n    from, or merely link (or bind by name) to the interfaces of, the Work and\n    Derivative Works thereof.\n\n    \"Contribution\" shall mean any work of authorship, including the original\n    version of the Work and any modifications or additions to that Work or\n    Derivative Works thereof, that is intentionally submitted to Licensor for\n    inclusion in the Work by the copyright owner or by an individual or\n    Legal Entity authorized to submit on behalf of the copyright owner.\n    For the purposes of this definition, \"submitted\" means any form of\n    electronic, verbal, or written communication sent to the Licensor or its\n    representatives, including but not limited to communication on electronic\n    mailing lists, source code control systems, and issue tracking systems\n    that are managed by, or on behalf of, the Licensor for the purpose of\n    discussing and improving the Work, but excluding communication that is\n    conspicuously marked or otherwise designated in writing by the copyright\n    owner as \"Not a Contribution.\"\n\n    \"Contributor\" shall mean Licensor and any individual or Legal Entity on\n    behalf of whom a Contribution has been received by Licensor and\n    subsequently incorporated within the Work.\n\n2. Grant of Copyright License.\n\n    Subject to the terms and conditions of this License, each Contributor\n    hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,\n    royalty-free, irrevocable copyright license to reproduce, prepare\n    Derivative Works of, publicly display, publicly perform, sublicense,\n    and distribute the Work and such Derivative Works in\n    Source or Object form.\n\n3. Grant of Patent License.\n\n    Subject to the terms and conditions of this License, each Contributor\n    hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,\n    royalty-free, irrevocable (except as stated in this section) patent\n    license to make, have made, use, offer to sell, sell, import, and\n    otherwise transfer the Work, where such license applies only to those\n    patent claims licensable by such Contributor that are necessarily\n    infringed by their Contribution(s) alone or by combination of their\n    Contribution(s) with the Work to which such Contribution(s) was submitted.\n    If You institute patent litigation against any entity (including a\n    cross-claim or counterclaim in a lawsuit) alleging that the Work or a\n    Contribution incorporated within the Work constitutes direct or\n    contributory patent infringement, then any patent licenses granted to\n    You under this License for that Work shall terminate as of the date such\n    litigation is filed.\n\n4. Redistribution.\n\n    You may reproduce and distribute copies of the Work or Derivative Works\n    thereof in any medium, with or without modifications, and in Source or\n    Object form, provided that You meet the following conditions:\n\n    1. You must give any other recipients of the Work or Derivative Works a\n    copy of this License; and\n\n    2. You must cause any modified files to carry prominent notices stating\n    that You changed the files; and\n\n    3. You must retain, in the Source form of any Derivative Works that You\n    distribute, all copyright, patent, trademark, and attribution notices from\n    the Source form of the Work, excluding those notices that do not pertain\n    to any part of the Derivative Works; and\n\n    4. If the Work includes a \"NOTICE\" text file as part of its distribution,\n    then any Derivative Works that You distribute must include a readable copy\n    of the attribution notices contained within such NOTICE file, excluding\n    those notices that do not pertain to any part of the Derivative Works,\n    in at least one of the following places: within a NOTICE text file\n    distributed as part of the Derivative Works; within the Source form or\n    documentation, if provided along with the Derivative Works; or, within a\n    display generated by the Derivative Works, if and wherever such\n    third-party notices normally appear. The contents of the NOTICE file are\n    for informational purposes only and do not modify the License.\n    You may add Your own attribution notices within Derivative Works that You\n    distribute, alongside or as an addendum to the NOTICE text from the Work,\n    provided that such additional attribution notices cannot be construed\n    as modifying the License.\n\n    You may add Your own copyright statement to Your modifications and may\n    provide additional or different license terms and conditions for use,\n    reproduction, or distribution of Your modifications, or for any such\n    Derivative Works as a whole, provided Your use, reproduction, and\n    distribution of the Work otherwise complies with the conditions\n    stated in this License.\n\n5. Submission of Contributions.\n\n    Unless You explicitly state otherwise, any Contribution intentionally\n    submitted for inclusion in the Work by You to the Licensor shall be under\n    the terms and conditions of this License, without any additional\n    terms or conditions. Notwithstanding the above, nothing herein shall\n    supersede or modify the terms of any separate license agreement you may\n    have executed with Licensor regarding such Contributions.\n\n6. Trademarks.\n\n    This License does not grant permission to use the trade names, trademarks,\n    service marks, or product names of the Licensor, except as required for\n    reasonable and customary use in describing the origin of the Work and\n    reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\n    Unless required by applicable law or agreed to in writing, Licensor\n    provides the Work (and each Contributor provides its Contributions)\n    on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n    either express or implied, including, without limitation, any warranties\n    or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS\n    FOR A PARTICULAR PURPOSE. You are solely responsible for determining the\n    appropriateness of using or redistributing the Work and assume any risks\n    associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability.\n\n    In no event and under no legal theory, whether in tort\n    (including negligence), contract, or otherwise, unless required by\n    applicable law (such as deliberate and grossly negligent acts) or agreed\n    to in writing, shall any Contributor be liable to You for damages,\n    including any direct, indirect, special, incidental, or consequential\n    damages of any character arising as a result of this License or out of\n    the use or inability to use the Work (including but not limited to damages\n    for loss of goodwill, work stoppage, computer failure or malfunction,\n    or any and all other commercial damages or losses), even if such\n    Contributor has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\n    While redistributing the Work or Derivative Works thereof, You may choose\n    to offer, and charge a fee for, acceptance of support, warranty,\n    indemnity, or other liability obligations and/or rights consistent with\n    this License. However, in accepting such obligations, You may act only\n    on Your own behalf and on Your sole responsibility, not on behalf of any\n    other Contributor, and only if You agree to indemnify, defend, and hold\n    each Contributor harmless for any liability incurred by, or claims\n    asserted against, such Contributor by reason of your accepting any such\n    warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\n    To apply the Apache License to your work, attach the following boilerplate\n    notice, with the fields enclosed by brackets \"[]\" replaced with your own\n    identifying information. (Don't include the brackets!) The text should be\n    enclosed in the appropriate comment syntax for the file format. We also\n    recommend that a file or class name and description of purpose be included\n    on the same \"printed page\" as the copyright notice for easier\n    identification within third-party archives.\n\n        Copyright 1999-2017 Alibaba Group.\n\n        Licensed under the Apache License, Version 2.0 (the \"License\");\n        you may not use this file except in compliance with the License.\n        You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n\n        Unless required by applicable law or agreed to in writing, software\n        distributed under the License is distributed on an \"AS IS\" BASIS,\n        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express\n        or implied. See the License for the specific language governing\n        permissions and limitations under the License."
  },
  {
    "path": "p3c-formatter/eclipse-codestyle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<profiles version=\"12\">\n    <profile kind=\"CodeFormatterProfile\" name=\"P3C-CodeStyle\" version=\"13\">\n        <!--可变参数的... Idea没有对应的配置项，强制insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_ellipsis\" value=\"insert\"/>\n        <!--枚举值之间 Idea没有对应的配置项，强制insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations\" value=\"insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=Java:SPACE_BEFORE_COMMA-->\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=Java:SPACE_BEFORE_COMMA\n        由于IDEA只有一个SPACE_BEFORE_COMMA选项，所以统一设置 insert_space_before_comma 为 do not insert\n        -->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments\"\n                 value=\"do not insert\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations\"\n                 value=\"do not insert\"/>\n        <!--insert_space_before_comma end-->\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=Java:SPACE_AFTER_COMMA_IN_TYPE_ARGUMENTS-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments\" value=\"insert\"/>\n        <!--IDEA只有一个配置项SPACE_AFTER_COMMA，insert_space_after_comma*统一设置成insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation\" value=\"insert\"/>\n        <!--insert_space_after_comma end-->\n\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=Java:SPACE_BEFORE_COLON-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for\" value=\"insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=Java:SPACE_AFTER_COLON-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement\" value=\"insert\"/>\n\n        <!--IDEA不支持配置，默认do not insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case\" value=\"do not insert\"/>\n        <!--这个在Eclipse也没有找到配置的地方-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case\" value=\"do not insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_semicolon=Java:SPACE_BEFORE_SEMICOLON\n        程序导入的时候强制将SPACE_BEFORE_SEMICOLON设置为false\n        -->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for\" value=\"do not insert\"/>\n\n        <!--SPACE_AFTER_SEMICOLON=true-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources\" value=\"insert\"/>\n\n        <!--IDEA不支持配置,do not insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant\"\n                 value=\"do not insert\"/>\n        <setting\n                id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration\"\n                value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration\"\n                 value=\"do not insert\"/>\n\n        <!--IDEA不支持，使用默认-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator\" value=\"do not insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=Java:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_binary_operator\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_binary_operator\" value=\"insert\"/>\n\n        <!--IDEA不支持配置，使用如下值，两者对应-->\n        <setting\n                id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference\"\n                value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters\"\n                 value=\"do not insert\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters\"\n                 value=\"insert\"/>\n        <setting\n                id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference\"\n                value=\"do not insert\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments\"\n                 value=\"do not insert\"/>\n        <setting\n                id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference\"\n                value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters\"\n                 value=\"do not insert\"/>\n\n        <!--Java:SPACE_BEFORE_OPENING_ANGLE_BRACKET_IN_TYPE_PARAMETER-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters\"\n                 value=\"do not insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=Java:SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENT-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments\"\n                 value=\"do not insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=Java:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block\" value=\"insert\"/>\n\n        <!--IDEA使用了对应的配置：Java:SPACE_WITHIN_ARRAY_INITIALIZER_BRACES，但感觉不太好，IDEA默认不插入，Eclipse也使用不插入-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer\"\n                 value=\"do not insert\"/>\n\n        <!--use default insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return\"\n                 value=\"insert\"/>\n\n        <!--use default do not insert -->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch\" value=\"do not insert\"/>\n\n\n        <!--use default insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw\"\n                 value=\"insert\"/>\n\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=Java:SPACE_BEFORE_SWITCH_LBRACE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch\" value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=Java:SPACE_BEFORE_CLASS_LBRACE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration\"\n                 value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=Java:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block\" value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=Java:SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer\"\n                 value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=Java:SPACE_BEFORE_METHOD_LBRACE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration\"\n                 value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=Java:SPACE_AFTER_QUEST-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional\" value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=Java:SPACE_BEFORE_QUEST-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional\" value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=Java:SPACE_BEFORE_ANOTATION_PARAMETER_LIST-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation\"\n                 value=\"do not insert\"/>\n\n        <!--use default do not insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_ellipsis\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast\" value=\"do not insert\"/>\n        <setting\n                id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration\"\n                value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression\"\n                 value=\"do not insert\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference\"\n                 value=\"do not insert\"/>\n\n\n        <!--下面两个对应IDEA中的一个配置Java:SPACE_AROUND_ASSIGNMENT_OPERATORS，使用insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator\" value=\"insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=Java:SPACE_BEFORE_CATCH_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch\" value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=Java:SPACE_BEFORE_METHOD_CALL_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation\"\n                 value=\"do not insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=Java:SPACE_BEFORE_TRY_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try\" value=\"insert\"/>\n\n        <!--下面两个对应IDEA中的一个配置Java:SPACE_AROUND_UNARY_OPERATOR，使用do not insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_unary_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_unary_operator\" value=\"do not insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=Java:SPACE_BEFORE_IF_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if\" value=\"insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=Java:SPACE_BEFORE_WHILE_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while\" value=\"insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=Java:SPACE_AFTER_TYPE_CAST-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast\" value=\"do not insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=Java:SPACE_BEFORE_METHOD_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration\"\n                 value=\"do not insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=Java:SPACE_BEFORE_FOR_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for\" value=\"insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=Java:SPACE_BEFORE_SYNCHRONIZED_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized\" value=\"insert\"/>\n\n        <!--org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=Java:SPACE_BEFORE_SWITCH_PARENTHESES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch\" value=\"insert\"/>\n\n        <!--下面两个对应IDEA中的一个配置Java:SPACE_AROUND_LAMBDA_ARROW，使用insert-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow\" value=\"insert\"/>\n        <!--SPACE_WITHIN_EMPTY_ARRAY_INITIALIZER_BRACES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer\"\n                 value=\"do not insert\"/>\n\n        <!--Idea -> Wrapping And Braces -> Simple classes in one line -->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration\" value=\"do not insert\"/>\n        <!--Idea -> Wrapping And Braces -> Simple method in one line -->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body\" value=\"do not insert\"/>\n        <!--因为Idea不支持配置，所以设置为 Idea默认值-->\n\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_label\" value=\"insert\"/>\n        <!--Idea可以通过Wrap Always实现 TODO-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type\" value=\"insert\"/>\n        <!--Idea -> Wrapping And Braces -> Simple block in one line -> do not select -->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block\" value=\"insert\"/>\n\n        <!--Idea -> Wrapping And Braces -> try statement -> catch.... (Java:CATCH_ON_NEW_LINE)-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement\"\n                 value=\"do not insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing\" value=\"do not insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=Java:ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer\"\n                 value=\"do not insert\"/>\n        <!--#org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=Java:ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer\"\n                 value=\"do not insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=Java:ELSE_ON_NEW_LINE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement\" value=\"do not insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=Java:WHILE_ON_NEW_LINE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement\"\n                 value=\"do not insert\"/>\n        <!--org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=Java:FINALLY_ON_NEW_LINE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement\"\n                 value=\"do not insert\"/>\n\n        <!--comment start-->\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.line_length\" value=\"120\"/>\n        <!--ENABLE_JAVADOC_FORMATTING-->\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_javadoc_comments\" value=\"true\"/>\n        <!--org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment\" value=\"false\"/>\n        <!--IDEA无对应设置，所以关闭对block comment的格式化 -->\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_block_comments\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries\" value=\"true\"/>\n\n        <!--org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=Java:KEEP_FIRST_COLUMN_COMMENT-->\n        <setting id=\"org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column\" value=\"false\"/>\n        <!--org.eclipse.jdt.core.formatter.use_on_off_tags=FORMATTER_TAGS_ENABLED-->\n        <setting id=\"org.eclipse.jdt.core.formatter.use_on_off_tags\" value=\"true\"/>\n        <!--org.eclipse.jdt.core.formatter.disabling_tag=FORMATTER_OFF_TAG-->\n        <setting id=\"org.eclipse.jdt.core.formatter.disabling_tag\" value=\"@formatter:off\"/>\n        <!--org.eclipse.jdt.core.formatter.enabling_tag=FORMATTER_ON_TAG-->\n        <setting id=\"org.eclipse.jdt.core.formatter.enabling_tag\" value=\"@formatter:on\"/>\n\n        <!--下面的没有IDEA对应项，在代码里面对IDEA中使用默认值即可,LINE_COMMENT_AT_FIRST_COLUMN BLOCK_COMMENT_AT_FIRST_COLUMN设置为false-->\n        <setting id=\"org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.indent_root_tags\" value=\"true\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments\"\n                 value=\"false\"/>\n\n\n        <setting id=\"org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_line_comments\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_header\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries\" value=\"true\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_source_code\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_html\" value=\"true\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.join_lines_in_comments\" value=\"true\"/>\n        <!--和IDEA保持一致，注释换行-->\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.indent_parameter_description\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter\" value=\"do not insert\"/>\n\n\n        <!--comment end-->\n\n        <!--org.eclipse.jdt.core.formatter.blank_lines_after_imports=Java:BLANK_LINES_AFTER_IMPORTS-->\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_imports\" value=\"1\"/>\n        <!--org.eclipse.jdt.core.formatter.blank_lines_before_imports=Java:BLANK_LINES_BEFORE_IMPORTS-->\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_imports\" value=\"1\"/>\n        <!--org.eclipse.jdt.core.formatter.blank_lines_after_package=Java:BLANK_LINES_AFTER_PACKAGE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_package\" value=\"1\"/>\n        <!--org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=Java:BLANK_LINES_AROUND_CLASS-->\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations\" value=\"1\"/>\n        <!--org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=Java:BLANK_LINES_BEFORE_METHOD_BODY-->\n        <setting id=\"org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body\" value=\"0\"/>\n        <!--org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=Java:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration\" value=\"0\"/>\n        <!--org.eclipse.jdt.core.formatter.blank_lines_before_field=Java:BLANK_LINES_AROUND_FIELD-->\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_field\" value=\"0\"/>\n        <!--org.eclipse.jdt.core.formatter.blank_lines_before_method=Java:BLANK_LINES_AROUND_METHOD-->\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_method\" value=\"1\"/>\n        <!--org.eclipse.jdt.core.formatter.blank_lines_before_package=Java:BLANK_LINES_BEFORE_PACKAGE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_package\" value=\"0\"/>\n\n        <!--下面IDEA没有对应设置，使用对应值即可-->\n        <setting id=\"org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines\" value=\"2147483647\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_member_type\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_import_groups\" value=\"1\"/>\n\n        <!--org.eclipse.jdt.core.formatter.indentation.size=Java:IndentOptions:INDENT_SIZE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.indentation.size\" value=\"4\"/>\n        <!--org.eclipse.jdt.core.formatter.continuation_indentation=Java:IndentOptions:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation\" value=\"1\"/>\n        <!--org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=Java:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header\" value=\"true\"/>\n        <!--org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=Java:IndentOptions:SMART_TABS-->\n        <setting id=\"org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations\" value=\"false\"/>\n        <!--org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=Java:INDENT_CASE_FROM_SWITCH-->\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch\" value=\"true\"/>\n        <!--KEEP_INDENTS_ON_EMPTY_LINES-->\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_empty_lines\" value=\"false\"/>\n        <!--org.eclipse.jdt.core.formatter.tabulation.size=Java:IndentOptions:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.tabulation.size\" value=\"4\"/>\n        <!--Java:IndentOptions:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.tabulation.char\" value=\"space\"/>\n\n\n        <!--下面IDEA没有对应设置，使用对应值即可-->\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_block\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header\"\n                 value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer\" value=\"1\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header\"\n                 value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_body\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header\"\n                 value=\"true\"/>\n\n\n        <!--Java:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_assignment\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_binary_expression\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_resources_in_try\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_conditional_expression\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer\" value=\"16\"/>\n\n        <!--下面没有对应的IDEA设置，Eclipse先使用对应值-->\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_enum_constants\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_type_parameters\" value=\"16\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration\" value=\"16\"/>\n\n\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_method_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_compact_if\" value=\"16\"/>\n\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_type_arguments\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression\"\n                 value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_multiple_fields\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header\" value=\"16\"/>\n\n        <!--IDEA默认配置在同一行，Eclipse使用对应值即可-->\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment\" value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation\" value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement\" value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration\"\n                 value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement\" value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause\" value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation\" value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause\" value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration\" value=\"common_lines\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration\" value=\"common_lines\"/>\n\n        <!--Java:BINARY_OPERATION_SIGN_ON_NEXT_LINE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.wrap_before_binary_operator\" value=\"true\"/>\n\n        <!--ASSIGNMENT_WRAP 需要设置为 WRAP_AS_NEEDED  WRAP_AS_NEEDED . Add in jdt.core-3.12，it's not work in previous version -->\n        <setting id=\"org.eclipse.jdt.core.formatter.wrap_before_assignment_operator\" value=\"false\"/>\n\n        <!--IDEA无配置项，Eclipse使用对应值即可-->\n        <setting id=\"org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.wrap_before_conditional_operator\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line\" value=\"false\"/>\n\n        <!--org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=Java:KEEP_CONTROL_STATEMENT_IN_ONE_LINE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line\" value=\"false\"/>\n        <!--org.eclipse.jdt.core.formatter.compact_else_if=Java:SPECIAL_ELSE_IF_TREATMENT-->\n        <setting id=\"org.eclipse.jdt.core.formatter.compact_else_if\" value=\"true\"/>\n        <!--Java:ALIGN_GROUP_FIELD_DECLARATIONS-->\n        <setting id=\"org.eclipse.jdt.core.formatter.align_type_members_on_columns\" value=\"false\"/>\n        <!--Java:<Programmatic>-->\n        <setting id=\"org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.join_wrapped_lines\" value=\"true\"/>\n\n        <!--统一为end_of_lint，IDEA默认一致-->\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_method_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_lambda_body\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block_in_case\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration\"\n                 value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_switch\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_array_initializer\" value=\"end_of_line\"/>\n\n\n        <!--        <setting id=\"org.eclipse.jdt.core.compiler.source\" value=\"1.8\"/>\n                <setting id=\"org.eclipse.jdt.core.compiler.compliance\" value=\"1.8\"/>\n                <setting id=\"org.eclipse.jdt.core.compiler.codegen.targetPlatform\" value=\"1.8\"/>\n                        <setting id=\"org.eclipse.jdt.core.compiler.problem.enumIdentifier\" value=\"error\"/>\n                                <setting id=\"org.eclipse.jdt.core.compiler.problem.assertIdentifier\" value=\"error\"/>\n                                        <setting id=\"org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode\" value=\"enabled\"/>\n                -->\n        <!--Java:KEEP_SIMPLE_BLOCKS_IN_ONE_LINE-->\n        <setting id=\"org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line\" value=\"false\"/>\n\n        <!--Java:CLASS_BRACE_STYLE，统一使用end_of_line TODO-->\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_constant\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_type_declaration\" value=\"end_of_line\"/>\n\n        <!--org.eclipse.jdt.core.formatter.lineSplit=RIGHT_MARGIN-->\n        <setting id=\"org.eclipse.jdt.core.formatter.lineSplit\" value=\"120\"/>\n    </profile>\n</profiles>\n"
  },
  {
    "path": "p3c-formatter/eclipse-codetemplate.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><templates><template autoinsert=\"true\" context=\"gettercomment_context\" deleted=\"false\" description=\"Comment for getter method\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.gettercomment\" name=\"gettercomment\">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert=\"true\" context=\"settercomment_context\" deleted=\"false\" description=\"Comment for setter method\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.settercomment\" name=\"settercomment\">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert=\"true\" context=\"constructorcomment_context\" deleted=\"false\" description=\"Comment for created constructors\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.constructorcomment\" name=\"constructorcomment\">/**\n * ${tags}\n */</template><template autoinsert=\"true\" context=\"filecomment_context\" deleted=\"false\" description=\"Comment for created Java files\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.filecomment\" name=\"filecomment\"/><template autoinsert=\"true\" context=\"typecomment_context\" deleted=\"false\" description=\"Comment for created types\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.typecomment\" name=\"typecomment\">/**\n * @author ${user}\n * @date ${currentDate:date('YYYY/MM/dd')}\n */</template><template autoinsert=\"true\" context=\"fieldcomment_context\" deleted=\"false\" description=\"Comment for fields\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.fieldcomment\" name=\"fieldcomment\">/**\n *\n */</template><template autoinsert=\"true\" context=\"methodcomment_context\" deleted=\"false\" description=\"Comment for non-overriding methods\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.methodcomment\" name=\"methodcomment\">/**\n * ${tags}\n */</template><template autoinsert=\"true\" context=\"overridecomment_context\" deleted=\"false\" description=\"Comment for overriding methods\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.overridecomment\" name=\"overridecomment\">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert=\"true\" context=\"delegatecomment_context\" deleted=\"false\" description=\"Comment for delegate methods\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.delegatecomment\" name=\"delegatecomment\">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert=\"true\" context=\"newtype_context\" deleted=\"false\" description=\"Newly created files\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.newtype\" name=\"newtype\">${filecomment}\n ${package_declaration}\n\n ${typecomment}\n ${type_declaration}</template><template autoinsert=\"true\" context=\"classbody_context\" deleted=\"false\" description=\"Code in new class type bodies\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.classbody\" name=\"classbody\">\n</template><template autoinsert=\"true\" context=\"interfacebody_context\" deleted=\"false\" description=\"Code in new interface type bodies\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.interfacebody\" name=\"interfacebody\">\n</template><template autoinsert=\"true\" context=\"enumbody_context\" deleted=\"false\" description=\"Code in new enum type bodies\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.enumbody\" name=\"enumbody\">\n</template><template autoinsert=\"true\" context=\"annotationbody_context\" deleted=\"false\" description=\"Code in new annotation type bodies\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.annotationbody\" name=\"annotationbody\">\n</template><template autoinsert=\"true\" context=\"catchblock_context\" deleted=\"false\" description=\"Code in new catch blocks\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.catchblock\" name=\"catchblock\">// ${todo} Auto-generated catch block\n ${exception_var}.printStackTrace();</template><template autoinsert=\"true\" context=\"methodbody_context\" deleted=\"false\" description=\"Code in created method stubs\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.methodbody\" name=\"methodbody\">// ${todo} Auto-generated method stub\n ${body_statement}</template><template autoinsert=\"true\" context=\"constructorbody_context\" deleted=\"false\" description=\"Code in created constructor stubs\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.constructorbody\" name=\"constructorbody\">${body_statement}\n // ${todo} Auto-generated constructor stub</template><template autoinsert=\"true\" context=\"getterbody_context\" deleted=\"false\" description=\"Code in created getters\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.getterbody\" name=\"getterbody\">return ${field};</template><template autoinsert=\"true\" context=\"setterbody_context\" deleted=\"false\" description=\"Code in created setters\" enabled=\"true\" id=\"org.eclipse.jdt.ui.text.codetemplates.setterbody\" name=\"setterbody\">${field} = ${param};</template></templates>"
  },
  {
    "path": "p3c-gitbook/.gitignore",
    "content": "# Node rules:\n## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n## Dependency directory\n## Commenting this out is preferred by some people, see\n## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git\nnode_modules\n\n# Book build output\n_book\n\n# eBook build output\n*.epub\n*.mobi\n*.pdf"
  },
  {
    "path": "p3c-gitbook/MySQL数据库/ORM映射.md",
    "content": "## (四) ORM映射\n1. 【强制】在表查询中，一律不要使用 * 作为查询的字段列表，需要哪些字段必须明确写明。 \n<br><span style=\"color:orange\">说明</span>：1）增加查询分析器解析成本。2）增减字段容易与resultMap配置不一致。 \n2. 【强制】POJO类的布尔属性不能加is，而数据库字段必须加is_，要求在resultMap中进行字段与属性之间的映射。 \n<br><span style=\"color:orange\">说明</span>：参见定义POJO类以及数据库字段定义规定，在<resultMap>中增加映射，是必须的。在MyBatis Generator生成的代码中，需要进行对应的修改。\n3. 【强制】不要用resultClass当返回参数，即使所有类属性名与数据库字段一一对应，也需要定义；反过来，每一个表也必然有一个与之对应。 \n<br><span style=\"color:orange\">说明</span>：配置映射关系，使字段与DO类解耦，方便维护。 \n4. 【强制】sql.xml配置参数使用：#{}，#param# 不要使用${} 此种方式容易出现SQL注入。 \n5. 【强制】iBATIS自带的queryForList(String statementName,int start,int size)不推荐使用。\n<br><span style=\"color:orange\">说明</span>：其实现方式是在数据库取到statementName对应的SQL语句的所有记录，再通过subList取start,size的子集合。 \n<br><span style=\"color:green\">正例</span>：\n        \n        Map<String, Object> map = new HashMap<String, Object>();    \n        map.put(\"start\", start);    \n        map.put(\"size\", size);\n\n6. 【强制】不允许直接拿HashMap与Hashtable作为查询结果集的输出。 \n<br><span style=\"color:orange\">说明</span>：resultClass=”Hashtable”，会置入字段名和属性值，但是值的类型不可控。\n7. 【强制】更新数据表记录时，必须同时更新记录对应的gmt_modified字段值为当前时间。\n8. 【推荐】不要写一个大而全的数据更新接口。传入为POJO类，不管是不是自己的目标更新字段，都进行update table set c1=value1,c2=value2,c3=value3; 这是不对的。执行SQL时，不要更新无改动的字段，一是易出错；二是效率低；三是增加binlog存储。 \n9. 【参考】`@Transactional`事务不要滥用。事务会影响数据库的QPS，另外使用事务的地方需要考虑各方面的回滚方案，包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。 \n10. 【参考】`<isEqual>`中的compareValue是与属性值对比的常量，一般是数字，表示相等时带上此条件；`<isNotEmpty>`表示不为空且不为null时执行；`<isNotNull>`表示不为null值时执行。  "
  },
  {
    "path": "p3c-gitbook/MySQL数据库/SQL语句.md",
    "content": "## (三) SQL语句 \n1. 【强制】不要使用count(列名)或count(常量)来替代count(*)，count(*)是SQL92定义的标准统计行数的语法，跟数据库无关，跟NULL和非NULL无关。 \n<br><span style=\"color:orange\">说明</span>：count(*)会统计值为NULL的行，而count(列名)不会统计此列为NULL值的行。 \n2. 【强制】count(distinct col) 计算该列除NULL之外的不重复行数，注意 count(distinct col1, col2) 如果其中一列全为NULL，那么即使另一列有不同的值，也返回为0。 \n3. 【强制】当某一列的值全是NULL时，count(col)的返回结果为0，但sum(col)的返回结果为NULL，因此使用sum()时需注意NPE问题。 \n<br><span style=\"color:green\">正例</span>：可以使用如下方式来避免sum的NPE问题：\n<pre>SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table; </pre>\n4. 【强制】使用`ISNULL()`来判断是否为NULL值。 说明：NULL与任何值的直接比较都为NULL。  \n1） `NULL<>NULL`的返回结果是NULL，而不是`false`。  \n2） `NULL=NULL`的返回结果是NULL，而不是`true`。  \n3） `NULL<>1`的返回结果是NULL，而不是`true`。 \n5. 【强制】 在代码中写分页查询逻辑时，若count为0应直接返回，避免执行后面的分页语句。 \n6. 【强制】不得使用外键与级联，一切外键概念必须在应用层解决。 \n<br><span style=\"color:orange\">说明</span>：以学生和成绩的关系为例，学生表中的student_id是主键，那么成绩表中的student_id则为外键。如果更新学生表中的student_id，同时触发成绩表中的student_id更新，即为级联更新。外键与级联更新适用于单机低并发，不适合分布式、高并发集群；级联更新是强阻塞，存在数据库更新风暴的风险；外键影响数据库的插入速度。 \n7. 【强制】禁止使用存储过程，存储过程难以调试和扩展，更没有移植性。 \n8. 【强制】数据订正（特别是删除、修改记录操作）时，要先select，避免出现误删除，确认无误才能执行更新语句。 \n9. 【推荐】in操作能避免则避免，若实在避免不了，需要仔细评估in后边的集合元素数量，控制在1000个之内。 \n10. 【参考】如果有全球化需要，所有的字符存储与表示，均以utf-8编码，注意字符统计函数的区别。 \n<br><span style=\"color:orange\">说明</span>：\n<pre>SELECT LENGTH(\"轻松工作\")； 返回为12\nSELECT CHARACTER_LENGTH(\"轻松工作\")； 返回为4</pre>\n如果需要存储表情，那么选择utf8mb4来进行存储，注意它与utf-8编码的区别。 \n11. 【参考】 TRUNCATE TABLE 比 DELETE 速度快，且使用的系统和事务日志资源少，但TRUNCATE无事务且不触发trigger，有可能造成事故，故不建议在开发代码中使用此语句。 \n<br><span style=\"color:orange\">说明</span>：TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同。 "
  },
  {
    "path": "p3c-gitbook/MySQL数据库/建表规约.md",
    "content": "# 五、MySQL数据库\n## (一) 建表规约\n1. 【强制】表达是与否概念的字段，必须使用is_xxx的方式命名，数据类型是unsigned tinyint（ 1表示是，0表示否）。 \n<br><span style=\"color:orange\">说明</span>：任何字段如果为非负数，必须是`unsigned`。 \n<br><span style=\"color:green\">正例</span>：表达逻辑删除的字段名`is_deleted`，1表示删除，0表示未删除。 \n2. 【强制】表名、字段名必须使用小写字母或数字，禁止出现数字开头，禁止两个下划线中间只出现数字。数据库字段名的修改代价很大，因为无法进行预发布，所以字段名称需要慎重考虑。 <br><span style=\"color:orange\">说明</span>：MySQL在Windows下不区分大小写，但在Linux下默认是区分大小写。因此，数据库名、表名、字段名，都不允许出现任何大写字母，避免节外生枝。 <br><span style=\"color:green\">正例</span>：aliyun_admin，rdc_config，level3_name <br><span style=\"color:red\">反例</span>：AliyunAdmin，rdcConfig，level_3_name \n3. 【强制】表名不使用复数名词。 \n<br><span style=\"color:orange\">说明</span>：表名应该仅仅表示表里面的实体内容，不应该表示实体数量，对应于DO类名也是单数形式，符合表达习惯。 \n4. 【强制】禁用保留字，如`desc`、`range`、`match`、`delayed`等，请参考MySQL官方保留字。 \n5. 【强制】主键索引名为pk_字段名；唯一索引名为uk_字段名；普通索引名则为idx_字段名。 \n<br><span style=\"color:orange\">说明</span>：pk_ 即primary key；uk_ 即 unique key；idx_ 即index的简称。 \n6. 【强制】小数类型为decimal，禁止使用float和double。 \n<br><span style=\"color:orange\">说明</span>：float和double在存储的时候，存在精度损失的问题，很可能在值的比较时，得到不正确的结果。如果存储的数据范围超过decimal的范围，建议将数据拆成整数和小数分开存储。 \n7. 【强制】如果存储的字符串长度几乎相等，使用char定长字符串类型。 \n8. 【强制】varchar是可变长字符串，不预先分配存储空间，长度不要超过5000，如果存储长度大于此值，定义字段类型为text，独立出来一张表，用主键来对应，避免影响其它字段索引效率。 \n9. 【强制】表必备三字段：id, gmt_create, gmt_modified。 \n<br><span style=\"color:orange\">说明</span>：其中id必为主键，类型为unsigned bigint、单表时自增、步长为1。gmt_create, gmt_modified的类型均为datetime类型，前者现在时表示主动创建，后者过去分词表示被动更新。 \n10. 【推荐】表的命名最好是加上“业务名称_表的作用”。 \n<br><span style=\"color:green\">正例</span>：alipay_task / force_project / trade_config \n11. 【推荐】库名与应用名称尽量一致。 \n12. 【推荐】如果修改字段含义或对字段表示的状态追加时，需要及时更新字段注释。 \n13. 【推荐】字段允许适当冗余，以提高查询性能，但必须考虑数据一致。冗余字段应遵循：  \n1）不是频繁修改的字段。  \n2）不是varchar超长字段，更不能是text字段。\n <br><span style=\"color:green\">正例</span>：商品类目名称使用频率高，字段长度短，名称基本一成不变，可在相关联的表中冗余存储类目名称，避免关联查询。 \n14. 【推荐】单表行数超过500万行或者单表容量超过2GB，才推荐进行分库分表。 <br><span style=\"color:orange\">说明</span>：如果预计三年后的数据量根本达不到这个级别，请不要在创建表时就分库分表。 \n15. 【参考】合适的字符存储长度，不但节约数据库表空间、节约索引存储，更重要的是提升检索速度。 <br><span style=\"color:green\">正例</span>：如下表，其中无符号值可以避免误存负数，且扩大了表示范围。 \n\n| 对象  | 年龄区间 | 类型  | 字节  |\n| ------------- |:-------------| :----- |:----- |\n| 人 |150岁之内  | unsigned tinyint|1|\n| 龟 |数百岁 | unsigned smallint |2|\n| 恐龙化石 |数千万岁 | unsigned int |4|\n| 太阳 |约50亿年 | unsigned bigint |8|"
  },
  {
    "path": "p3c-gitbook/MySQL数据库/索引规约.md",
    "content": "## (二) 索引规约\n1. 【强制】业务上具有唯一特性的字段，即使是多个字段的组合，也必须建成唯一索引。 \n<br><span style=\"color:orange\">说明</span>：不要以为唯一索引影响了insert速度，这个速度损耗可以忽略，但提高查找速度是明显的；另外，即使在应用层做了非常完善的校验控制，只要没有唯一索引，根据墨菲定律，必然有脏数据产生。 \n2. 【强制】超过三个表禁止join。需要join的字段，数据类型必须绝对一致；多表关联查询时，保证被关联的字段需要有索引。 \n<br><span style=\"color:orange\">说明</span>：即使双表join也要注意表索引、SQL性能。 \n3. 【强制】在varchar字段上建立索引时，必须指定索引长度，没必要对全字段建立索引，根据实际文本区分度决定索引长度即可。 \n<br><span style=\"color:orange\">说明</span>：索引的长度与区分度是一对矛盾体，一般对字符串类型数据，长度为20的索引，区分度会高达90%以上，可以使用count(distinct left(列名, 索引长度))/count(*)的区分度来确定。 \n4. 【强制】页面搜索严禁左模糊或者全模糊，如果需要请走搜索引擎来解决。 \n<br><span style=\"color:orange\">说明</span>：索引文件具有B-Tree的最左前缀匹配特性，如果左边的值未确定，那么无法使用此索引。\n5. 【推荐】如果有order by的场景，请注意利用索引的有序性。order by 最后的字段是组合索引的一部分，并且放在索引组合顺序的最后，避免出现file_sort的情况，影响查询性能。 \n<br><span style=\"color:green\">正例</span>：where a=? and b=? order by c; 索引：a_b_c \n<br><span style=\"color:red\">反例</span>：索引中有范围查找，那么索引有序性无法利用，如：WHERE a>10 ORDER BY b; 索引a_b无法排序。 \n6. 【推荐】利用覆盖索引来进行查询操作，避免回表。 \n<br><span style=\"color:orange\">说明</span>：如果一本书需要知道第11章是什么标题，会翻开第11章对应的那一页吗？目录浏览一下就好，这个目录就是起到覆盖索引的作用。 \n<br><span style=\"color:green\">正例</span>：能够建立索引的种类分为主键索引、唯一索引、普通索引三种，而覆盖索引只是一种查询的一种效果，用explain的结果，extra列会出现：using index。 \n7. 【推荐】利用延迟关联或者子查询优化超多分页场景。 <br><span style=\"color:orange\">说明</span>：MySQL并不是跳过offset行，而是取offset+N行，然后返回放弃前offset行，返回N行，那当offset特别大的时候，效率就非常的低下，要么控制返回的总页数，要么对超过特定阈值的页数进行SQL改写。 \n<br><span style=\"color:green\">正例</span>：先快速定位需要获取的id段，然后再关联：       \n<pre>SELECT a.* FROM 表1 a, (select id from 表1 where 条件 LIMIT 100000,20 ) b where a.id=b.id </pre>\n8. 【推荐】 SQL性能优化的目标：至少要达到 range 级别，要求是ref级别，如果可以是consts最好。 \n<br><span style=\"color:orange\">说明</span>：  \n1）consts 单表中最多只有一个匹配行（主键或者唯一索引），在优化阶段即可读取到数据。  \n2）ref 指的是使用普通的索引（normal index）。  \n3）range 对索引进行范围检索。 <br><span style=\"color:red\">反例</span>：explain表的结果，type=index，索引物理文件全扫描，速度非常慢，这个index级别比较range还低，与全表扫描是小巫见大巫。 \n9. 【推荐】建组合索引的时候，区分度最高的在最左边。 <br><span style=\"color:green\">正例</span>：如果where a=? and b=? ，a列的几乎接近于唯一值，那么只需要单建idx_a索引即可。 \n<br><span style=\"color:orange\">说明</span>：存在非等号和等号混合判断条件时，在建索引时，请把等号条件的列前置。如：where a>? and b=? 那么即使a的区分度更高，也必须把b放在索引的最前列。 \n10. 【推荐】防止因字段类型不同造成的隐式转换，导致索引失效。 \n11. 【参考】创建索引时避免有如下极端误解：  1）宁滥勿缺。认为一个查询就需要建一个索引。  2）宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。  3）抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。 "
  },
  {
    "path": "p3c-gitbook/README.md",
    "content": "## <center>前言</center>\n\n&nbsp;&nbsp;&nbsp;&nbsp;《阿里巴巴Java开发手册》是阿里巴巴集团技术团队的集体智慧结晶和经验总结，经历了多次大规模一线实战的检验及不断的完善，系统化地整理成册，回馈给广大开发者。现代软件行业的高速发展对开发者的综合素质要求越来越高，因为不仅是编程知识点，其它维度的知识点也会影响到软件的最终交付质量。比如：数据库的表结构和索引设计缺陷可能带来软件上的架构缺陷或性能风险；工程结构混乱导致后续维护艰难；没有鉴权的漏洞代码易被黑客攻击等等。所以本手册以Java开发者为中心视角，划分为编程规约、异常日志、单元测试、安全规约、工程结构、MySQL数据库六个维度，再根据内容特征，细分成若干二级子目录。根据约束力强弱及故障敏感性，规约依次分为强制、推荐、参考三大类。对于规约条目的延伸信息中，“说明”对内容做了适当扩展和解释；“正例”提倡什么样的编码和实现方式；“反例”说明需要提防的雷区，以及真实的错误案例。 \n<br>&nbsp;&nbsp;&nbsp;&nbsp;本手册的愿景是<strong>码出高效，码出质量</strong>。现代软件架构都需要协同开发完成，高效协作即降低协同成本，提升沟通效率，所谓无规矩不成方圆，无规范不能协作。众所周知，制订交通法规表面上是要限制行车权，实际上是保障公众的人身安全。试想如果没有限速，没有红绿灯，谁还敢上路行驶。对软件来说，适当的规范和标准绝不是消灭代码内容的创造性、优雅性，而是限制过度个性化，以一种普遍认可的统一方式一起做事，提升协作效率。代码的字里行间流淌的是软件生命中的血液，质量的提升是尽可能少踩坑，杜绝踩重复的坑，切实提升质量意识。 \n<br>&nbsp;&nbsp;&nbsp;&nbsp;考虑到可以零距离地与众多开发同学进行互动，决定未来在线维护《手册》内容，此1.3.1的PDF版本，是对外释放的最终纪念版，铭记发布第一版以来的358天旅程；我们已经在杭州云栖大会上进行了阿里巴巴Java开发规约插件[点此下载](https://github.com/alibaba/p3c)，阿里云效（一站式企业协同研发云）也集成了代码规约扫描引擎。最后，《码出高效——阿里巴巴Java开发手册详解》即将出版，敬请关注。 \n\n\n\n> 当前gitbook已经和最新版规约内容不一致，请参考最新版规约。\n"
  },
  {
    "path": "p3c-gitbook/SUMMARY.md",
    "content": "# Summary\n\n* [前言](README.md)\n* 一、编程规约\n  - [（一）命名风格](编程规约/命名风格.md)\n  - [（二）常量定义](编程规约/常量定义.md)\n  - [（三）代码格式](编程规约/代码格式.md)\n  - [（四）OOP规范](编程规约/OOP规范.md)\n  - [（五）集合处理](编程规约/集合处理.md)\n  - [（六）并发处理](编程规约/并发处理.md)\n  - [（七）控制语句](编程规约/控制语句.md)\n  - [（八）注释规约](编程规约/注释规约.md)\n* 二、异常日志\n  - [（一）异常处理](异常日志/异常处理.md)\n  - [（二）日志规范](异常日志/日志规约.md)\n  - [（三）其他](异常日志/其他.md)\n* [三、单元测试](单元测试.md)\n* [四、安全规约](安全规约.md)\n* 五、MySQL数据库\n  - [（一）建表规约](MySQL数据库/建表规约.md)\n  - [（二）索引规约](MySQL数据库/索引规约.md)\n  - [（三）SQL语句](MySQL数据库/SQL语句.md)\n  - [（四）ORM映射](MySQL数据库/ORM映射.md)\n* 六、工程结构\n  - [（一）应用分层](工程结构/应用分层.md)\n  - [（二）二方库依赖](工程结构/二方库依赖.md)\n  - [（三）服务器](工程结构/服务器.md)\n* [附1：版本历史 ](版本历史.md)\n* [附2：本手册专有名词 ](本手册专有名词.md)"
  },
  {
    "path": "p3c-gitbook/book.json",
    "content": "{\n  \"styles\": {\n    \"website\": \"styles/website.css\"\n  },\n\n  \"plugins\": [\n    \"book-summary-scroll-position-saver\",\n    \"github\",\n    \"prism\",\n    \"-sharing\",\n    \"-highlight\"\n  ],\n  \n  \"pluginsConfig\": {\n    \"github\": {\n      \"url\": \"https://github.com/alibaba/p3c\"\n    }\n  }\n}\n"
  },
  {
    "path": "p3c-gitbook/styles/website.css",
    "content": ".gitbook-link {\n    display: none !important;\n}"
  },
  {
    "path": "p3c-gitbook/单元测试.md",
    "content": "## 三、单元测试 \n1. 【强制】好的单元测试必须遵守AIR原则。 \n<br><span style=\"color:orange\">说明</span>：单元测试在线上运行时，感觉像空气（AIR）一样并不存在，但在测试质量的保障上，却是非常关键的。好的单元测试宏观上来说，具有自动化、独立性、可重复执行的特点。 \n - A：Automatic（自动化） \n - I：Independent（独立性） \n - R：Repeatable（可重复） \n2. 【强制】单元测试应该是全自动执行的，并且非交互式的。测试用例通常是被定期执行的，执行过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试。单元测试中不准使用System.out来进行人肉验证，必须使用assert来验证。 \n3. 【强制】保持单元测试的独立性。为了保证单元测试稳定可靠且便于维护，单元测试用例之间决不能互相调用，也不能依赖执行的先后次序。 <br><span style=\"color:red\">反例</span>：method2需要依赖method1的执行，将执行结果作为method2的输入。 \n4. 【强制】单元测试是可以重复执行的，不能受到外界环境的影响。 \n<br><span style=\"color:orange\">说明</span>：单元测试通常会被放到持续集成中，每次有代码check in时单元测试都会被执行。如果单测对外部环境（网络、服务、中间件等）有依赖，容易导致持续集成机制的不可用。 <br><span style=\"color:green\">正例</span>：为了不受外界环境影响，要求设计代码时就把SUT的依赖改成注入，在测试时用spring 这样的DI框架注入一个本地（内存）实现或者Mock实现。 \n5. 【强制】对于单元测试，要保证测试粒度足够小，有助于精确定位问题。单测粒度至多是类级别，一般是方法级别。 \n<br><span style=\"color:orange\">说明</span>：只有测试粒度小才能在出错时尽快定位到出错位置。单测不负责检查跨类或者跨系统的交互逻辑，那是集成测试的领域。 \n6. 【强制】核心业务、核心应用、核心模块的增量代码确保单元测试通过。 \n<br><span style=\"color:orange\">说明</span>：新增代码及时补充单元测试，如果新增代码影响了原有单元测试，请及时修正。 \n7. 【强制】单元测试代码必须写在如下工程目录：src/test/java，不允许写在业务代码目录下。 \n<br><span style=\"color:orange\">说明</span>：源码构建时会跳过此目录，而单元测试框架默认是扫描此目录。 \n8. 【推荐】单元测试的基本目标：语句覆盖率达到70%；核心模块的语句覆盖率和分支覆盖率都要达到100% \n<br><span style=\"color:orange\">说明</span>：在工程规约的应用分层中提到的DAO层，Manager层，可重用度高的Service，都应该进行单元测试。   \n9. 【推荐】编写单元测试代码遵守BCDE原则，以保证被测试模块的交付质量。 \n - B：Border，边界值测试，包括循环边界、特殊取值、特殊时间点、数据顺序等。 \n - C：Correct，正确的输入，并得到预期的结果。 \n - D：Design，与设计文档相结合，来编写单元测试。 \n -  E：Error，强制错误信息输入（如：非法数据、异常流程、非业务允许输入等），并得到预期的结果。 \n10. 【推荐】对于数据库相关的查询，更新，删除等操作，不能假设数据库里的数据是存在的，或者直接操作数据库把数据插入进去，请使用程序插入或者导入数据的方式来准备数据。 <br><span style=\"color:red\">反例</span>：删除某一行数据的单元测试，在数据库中，先直接手动增加一行作为删除目标，但是这一行新增数据并不符合业务插入规则，导致测试结果异常。 \n11. 【推荐】和数据库相关的单元测试，可以设定自动回滚机制，不给数据库造成脏数据。或者对单元测试产生的数据有明确的前后缀标识。 <br><span style=\"color:green\">正例</span>：在RDC内部单元测试中，使用RDC_UNIT_TEST_的前缀标识数据。 \n12. 【推荐】对于不可测的代码建议做必要的重构，使代码变得可测，避免为了达到测试要求而书写不规范测试代码。 \n13. 【推荐】在设计评审阶段，开发人员需要和测试人员一起确定单元测试范围，单元测试最好覆盖所有测试用例（UC）。 \n14. 【推荐】单元测试作为一种质量保障手段，不建议项目发布后补充单元测试用例，建议在项目提测前完成单元测试。 \n15. 【参考】为了更方便地进行单元测试，业务代码应避免以下情况：\n - 构造方法中做的事情过多。 \n - 存在过多的全局变量和静态方法。 \n - 存在过多的外部依赖。 \n - 存在过多的条件语句。 \n <br><span style=\"color:orange\">说明</span>：多层条件语句建议使用卫语句、策略模式、状态模式等方式重构。 \n16. 【参考】不要对单元测试存在如下误解： \n - 那是测试同学干的事情。本文是开发手册，凡是本文内容都是与开发同学强相关的。\n - 单元测试代码是多余的。汽车的整体功能与各单元部件的测试正常与否是强相关的。 \n - 单元测试代码不需要维护。一年半载后，那么单元测试几乎处于废弃状态。 \n - 单元测试与线上故障没有辩证关系。好的单元测试能够最大限度地规避线上故障。 "
  },
  {
    "path": "p3c-gitbook/安全规约.md",
    "content": "## 四、安全规约 \n1. 【强制】隶属于用户个人的页面或者功能必须进行权限控制校验。 \n<br><span style=\"color:orange\">说明</span>：防止没有做水平权限校验就可随意访问、修改、删除别人的数据，比如查看他人的私信内容、修改他人的订单。 \n2. 【强制】用户敏感数据禁止直接展示，必须对展示数据进行脱敏。 \n<br><span style=\"color:orange\">说明</span>：个人手机号码显示为:158****9119，隐藏中间4位，防止隐私泄露。 \n3. 【强制】用户输入的SQL参数严格使用参数绑定或者METADATA字段值限定，防止SQL注入，禁止字符串拼接SQL访问数据库。 \n4. 【强制】用户请求传入的任何参数必须做有效性验证。 \n<br><span style=\"color:orange\">说明</span>：忽略参数校验可能导致： \n - page size过大导致内存溢出 \n - 恶意order by导致数据库慢查询 \n - 任意重定向 \n - SQL注入 \n - 反序列化注入 \n - 正则输入源串拒绝服务ReDoS \n <br><span style=\"color:orange\">说明</span>：Java代码用正则来验证客户端的输入，有些正则写法验证普通用户输入没有问题，但是如果攻击人员使用的是特殊构造的字符串来验证，有可能导致死循环的结果。 \n5. 【强制】禁止向HTML页面输出未经安全过滤或未正确转义的用户数据。 \n6. 【强制】表单、AJAX提交必须执行CSRF安全过滤。 \n<br><span style=\"color:orange\">说明</span>：CSRF(Cross-site request forgery)跨站请求伪造是一类常见编程漏洞。对于存在CSRF漏洞的应用/网站，攻击者可以事先构造好URL，只要受害者用户一访问，后台便在用户不知情情况下对数据库中用户参数进行相应修改。 \n7. 【强制】在使用平台资源，譬如短信、邮件、电话、下单、支付，必须实现正确的防重放限制，如数量限制、疲劳度控制、验证码校验，避免被滥刷导致资损。 \n<br><span style=\"color:orange\">说明</span>：如注册时发送验证码到手机，如果没有限制次数和频率，那么可以利用此功能骚扰到其它用户，并造成短信平台资源浪费。 \n8. 【推荐】发贴、评论、发送即时消息等用户生成内容的场景必须实现防刷、文本内容违禁词过滤等风控策略。 "
  },
  {
    "path": "p3c-gitbook/工程结构/二方库依赖.md",
    "content": "## (二) 二方库依赖\n\n1. 【强制】定义GAV遵从以下规则：  \n1） `G`roupID格式：com.{公司/BU }.业务线.[子业务线]，最多4级。   \n<span style=\"color:orange\">说明</span>：{公司/BU} 例如：alibaba/taobao/tmall/aliexpress等BU一级；子业务线可选。   \n<span style=\"color:green\">正例</span>：com.taobao.jstorm 或 com.alibaba.dubbo.register\n<br>2） `A`rtifactID格式：产品线名-模块名。语义不重复不遗漏，先到中央仓库去查证一下。\n<br><span style=\"color:green\">正例</span>：dubbo-client / fastjson-api / jstorm-tool  \n3） `V`ersion：详细规定参考下方。 \n2. 【强制】二方库版本号命名方式：主版本号.次版本号.修订号  \n1） <strong>主版本号</strong>：产品方向改变，或者大规模API不兼容，或者架构不兼容升级。   \n2） <strong>次版本号</strong>：保持相对兼容性，增加主要功能特性，影响范围极小的API不兼容修改。  \n3） <strong>修订号</strong>：保持完全兼容性，修复BUG、新增次要功能特性等。  \n说明：注意起始版本号必须为：*1.0.0*，而不是0.0.1   正式发布的类库必须先去中央仓库进行查证，使版本号有延续性，正式版本号不允许覆盖升级。如当前版本：1.3.3，那么下一个合理的版本号：1.3.4 或 1.4.0 或 2.0.0 \n3. 【强制】线上应用不要依赖SNAPSHOT版本（安全包除外）。<br>\n<span style=\"color:orange\">说明</span>：不依赖SNAPSHOT版本是保证应用发布的幂等性。另外，也可以加快编译时的打包构建。  \n4. 【强制】二方库的新增或升级，保持除功能点之外的其它jar包仲裁结果不变。如果有改变，必须明确评估和验证，建议进行`dependency:resolve`前后信息比对，如果仲裁结果完全不一致，那么通过`dependency:tree`命令，找出差异点，进行`<excludes>`排除jar包。 \n5. 【强制】二方库里可以定义枚举类型，参数可以使用枚举类型，但是接口返回值不允许使用枚举类型或者包含枚举类型的POJO对象。 \n6. 【强制】依赖于一个二方库群时，必须定义一个统一的版本变量，避免版本号不一致。 <br>\n<span style=\"color:orange\">说明</span>：依赖springframework-core,-context,-beans，它们都是同一个版本，可以定义一个变量来保存版本：${spring.version}，定义依赖的时候，引用该版本。\n7. 【强制】禁止在子项目的pom依赖中出现相同的GroupId，相同的ArtifactId，但是不同的Version。\n<br><span style=\"color:orange\">说明</span>：在本地调试时会使用各子项目指定的版本号，但是合并成一个war，只能有一个版本号出现在最后的lib目录中。可能出现线下调试是正确的，发布到线上却出故障的问题。 \n8. 【推荐】所有pom文件中的依赖声明放在`<dependencies>`语句块中，所有版本仲裁放在`<dependencyManagement>`语句块中。 \n<br><span style=\"color:orange\">说明</span>：`<dependencyManagement>`里只是声明版本，并不实现引入，因此子项目需要显式的声明依赖，version和scope都读取自父pom。而`<dependencies>`所有声明在主pom的`<dependencies>`里的依赖都会自动引入，并默认被所有的子项目继承。 \n9. 【推荐】二方库不要有配置项，最低限度不要再增加配置项。 \n10. 【参考】为避免应用二方库的依赖冲突问题，二方库发布者应当遵循以下原则：<br> \n1）精简可控原则。移除一切不必要的API和依赖，只包含 Service API、必要的领域模型对象、Utils类、常量、枚举等。如果依赖其它二方库，尽量是provided引入，让二方库使用者去依赖具体版本号；无log具体实现，只依赖日志框架。<br>\n2）稳定可追溯原则。每个版本的变化应该被记录，二方库由谁维护，源码在哪里，都需要能方便查到。除非用户主动升级版本，否则公共二方库的行为不应该发生变化。  "
  },
  {
    "path": "p3c-gitbook/工程结构/应用分层.md",
    "content": "# 六、工程结构\n## (一) 应用分层 \n\n1. 【推荐】图中默认上层依赖于下层，箭头关系表示可直接依赖，如：开放接口层可以依赖于Web层，也可以直接依赖于Service层，依此类推：\n ![应用分层](../images/alibabaLevel.png)\n - 开放接口层：可直接封装Service方法暴露成RPC接口；通过Web封装成http接口；进行网关安全控制、流量控制等。 \n - 终端显示层：各个端的模板渲染并执行显示的层。当前主要是velocity渲染，JS渲染，JSP渲染，移动端展示等。 \n - Web层：主要是对访问控制进行转发，各类基本参数校验，或者不复用的业务简单处理等。 \n - Service层：相对具体的业务逻辑服务层。 \n - Manager层：通用业务处理层，它有如下特征：\n <br>1） 对第三方平台封装的层，预处理返回结果及转化异常信息；\n <br>2） 对Service层通用能力的下沉，如缓存方案、中间件通用处理；\n <br>3） 与DAO层交互，对多个DAO的组合复用。\n - DAO层：数据访问层，与底层MySQL、Oracle、Hbase等进行数据交互。 \n - 外部接口或第三方平台：包括其它部门RPC开放接口，基础平台，其它公司的HTTP接口。\n\n2. 【参考】（分层异常处理规约）在DAO层，产生的异常类型有很多，无法用细粒度的异常进行catch，使用catch(Exception e)方式，并throw new DAOException(e)，不需要打印日志，因为日志在Manager/Service层一定需要捕获并打印到日志文件中去，如果同台服务器再打日志，浪费性能和存储。在Service层出现异常时，必须记录出错日志到磁盘，尽可能带上参数信息，相当于保护案发现场。如果Manager层与Service同机部署，日志方式与DAO层处理一致，如果是单独部署，则采用与Service一致的处理方式。Web层绝不应该继续往上抛异常，因为已经处于顶层，如果意识到这个异常将导致页面无法正常渲染，那么就应该跳转到友好错误页面，加上用户容易理解的错误提示信息。开放接口层要将异常处理成错误码和错误信息方式返回。\n\n3. 【参考】分层领域模型规约：\n  - DO（Data Object）：与数据库表结构一一对应，通过DAO层向上传输数据源对象。\n  - DTO（Data Transfer Object）：数据传输对象，Service或Manager向外传输的对象。\n  - BO（Business Object）：业务对象。由Service层输出的封装业务逻辑的对象。\n  - AO（Application Object）：应用对象。在Web层与Service层之间抽象的复用对象模型，极为贴近展示层，复用度不高。\n  - VO（View Object）：显示层对象，通常是Web向模板渲染引擎层传输的对象。\n  - Query：数据查询对象，各层接收上层的查询请求。注意超过2个参数的查询封装，禁止使用Map类来传输。"
  },
  {
    "path": "p3c-gitbook/工程结构/服务器.md",
    "content": "## (三) 服务器\n1. 【推荐】高并发服务器建议调小TCP协议的`time_wait`超时时间。 说明：操作系统默认240秒后，才会关闭处于`time_wait`状态的连接，在高并发访问下，服务器端会因为处于`time_wait`的连接数太多，可能无法建立新的连接，所以需要在服务器上调小此等待值。 \n<br><span style=\"color:green\">正例</span>：在linux服务器上请通过变更/etc/sysctl.conf文件去修改该缺省值（秒）：\n  <pre>net.ipv4.tcp_fin_timeout = 30</pre>\n2. 【推荐】调大服务器所支持的最大文件句柄数（File Descriptor，简写为fd）。 \n<br><span style=\"color:orange\">说明</span>：主流操作系统的设计是将TCP/UDP连接采用与文件一样的方式去管理，即一个连接对应于一个fd。主流的linux服务器默认所支持最大fd数量为1024，当并发连接数很大时很\n容易因为fd不足而出现“open too many files”错误，导致新的连接无法建立。 建议将linux服务器所支持的最大句柄数调高数倍（与服务器的内存数量相关）。 \n3. 【推荐】给JVM设置-XX:+HeapDumpOnOutOfMemoryError参数，让JVM碰到OOM场景时输出dump信息。 \n<br><span style=\"color:orange\">说明</span>：OOM的发生是有概率的，甚至有规律地相隔数月才出现一例，出现时的现场信息对查错非常有价值。 \n4. 【推荐】在线上生产环境，JVM的Xms和Xmx设置一样大小的内存容量，避免在GC 后调整堆大小带来的压力。 \n5. 【参考】服务器内部重定向使用forward；外部重定向地址使用URL拼装工具类来生成，否则会带来URL维护不一致的问题和潜在的安全风险。 "
  },
  {
    "path": "p3c-gitbook/异常日志/其他.md",
    "content": "## (三) 其它 \n1. 【强制】在使用正则表达式时，利用好其预编译功能，可以有效加快正则匹配速度。 \n<br><span style=\"color:orange\">说明</span>：不要在方法体内定义：Pattern pattern = Pattern.compile(规则); \n2. 【强制】velocity调用POJO类的属性时，建议直接使用属性名取值即可，模板引擎会自动按规范调用POJO的getXxx()，如果是boolean基本数据类型变量（boolean命名不需要加is前缀），会自动调用isXxx()方法。 <br><span style=\"color:orange\">说明</span>：注意如果是Boolean包装类对象，优先调用getXxx()的方法。 \n3. 【强制】后台输送给页面的变量必须加$!{var}——中间的感叹号。 \n<br><span style=\"color:orange\">说明</span>：如果var=null或者不存在，那么${var}会直接显示在页面上。 \n4. 【强制】注意 Math.random() 这个方法返回是double类型，注意取值的范围 0≤x<1（能够取到零值，注意除零异常），如果想获取整数类型的随机数，不要将x放大10的若干倍然后取整，直接使用Random对象的`nextInt`或者`nextLong`方法。 \n5. 【强制】获取当前毫秒数\n<pre>System.currentTimeMillis();</pre> \n而不是\n<pre>new Date().getTime();</pre> \n<span style=\"color:orange\">说明</span>：如果想获取更加精确的纳秒级时间值，使用`System.nanoTime()`的方式。在JDK8中，针对统计时间等场景，推荐使用`Instant`类。 \n6. 【推荐】不要在视图模板中加入任何复杂的逻辑。 <br><span style=\"color:orange\">说明</span>：根据MVC理论，视图的职责是展示，不要抢模型和控制器的活。 \n7. 【推荐】任何数据结构的构造或初始化，都应指定大小，避免数据结构无限增长吃光内存。 \n8. 【推荐】及时清理不再使用的代码段或配置信息。 \n<br><span style=\"color:orange\">说明</span>：对于垃圾代码或过时配置，坚决清理干净，避免程序过度臃肿，代码冗余。 \n<br><span style=\"color:green\">正例</span>：对于暂时被注释掉，后续可能恢复使用的代码片断，在注释代码上方，统一规定使用三个斜杠(`///`)来说明注释掉代码的理由。 "
  },
  {
    "path": "p3c-gitbook/异常日志/异常处理.md",
    "content": "# 二、异常日志 \n## (一) 异常处理 \n1. 【强制】Java 类库中定义的可以通过预检查方式规避的RuntimeException异常不应该通过catch 的方式来处理，比如：NullPointerException，IndexOutOfBoundsException等等。 \n<span style=\"color:orange\">说明</span>：无法通过预检查的异常除外，比如，在解析字符串形式的数字时，不得不通过catch NumberFormatException来实现。 <br><span style=\"color:green\">正例</span>：<pre>if (obj != null) {...} </pre>\n<span style=\"color:red\">反例</span>：\n<pre>try { obj.method() } catch (NullPointerException e) {…}</pre>\n2. 【强制】异常不要用来做流程控制，条件控制。 \n<br><span style=\"color:orange\">说明</span>：异常设计的初衷是解决程序运行中的各种意外情况，且异常的处理效率比条件判断方式要低很多。 \n3. 【强制】catch时请分清稳定代码和非稳定代码，稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分异常类型，再做对应的异常处理。 \n<br><span style=\"color:orange\">说明</span>：对大段代码进行try-catch，使程序无法根据不同的异常做出正确的应激反应，也不利于定位问题，这是一种不负责任的表现。 \n<br><span style=\"color:green\">正例</span>：用户注册的场景中，如果用户输入非法字符，或用户名称已存在，或用户输入密码过于简单，在程序上作出分门别类的判断，并提示给用户。 \n4. 【强制】捕获异常是为了处理它，不要捕获了却什么都不处理而抛弃之，如果不想处理它，请将该异常抛给它的调用者。最外层的业务使用者，必须处理异常，将其转化为用户可以理解的内容。 \n5. 【强制】有try块放到了事务代码中，catch异常后，如果需要回滚事务，一定要注意手动回滚事务。 \n6. 【强制】finally块必须对资源对象、流对象进行关闭，有异常也要做try-catch。 \n<br><span style=\"color:orange\">说明</span>：如果JDK7及以上，可以使用try-with-resources方式。 \n7. 【强制】不要在finally块中使用return。 \n<br><span style=\"color:orange\">说明</span>：finally块中的return返回后方法结束执行，不会再执行try块中的return语句。 \n8. 【强制】捕获异常与抛异常，必须是完全匹配，或者捕获异常是抛异常的父类。 \n<br><span style=\"color:orange\">说明</span>：如果预期对方抛的是绣球，实际接到的是铅球，就会产生意外情况。 \n9. 【推荐】方法的返回值可以为null，不强制返回空集合，或者空对象等，必须添加注释充分\n<br><span style=\"color:orange\">说明</span>什么情况下会返回null值。 <br><span style=\"color:orange\">说明</span>：本手册明确防止NPE是调用者的责任。即使被调用方法返回空集合或者空对象，对调用者来说，也并非高枕无忧，必须考虑到远程调用失败、序列化失败、运行时异常等场景返回null的情况。 \n10. 【推荐】防止NPE，是程序员的基本修养，注意NPE产生的场景：  \n1）返回类型为基本数据类型，return包装数据类型的对象时，自动拆箱有可能产生NPE。     \n<span style=\"color:red\">反例</span>：public int f() { return Integer对象}， 如果为null，自动解箱抛NPE。  \n2） 数据库的查询结果可能为null。  \n3） 集合里的元素即使isNotEmpty，取出的数据元素也可能为null。  \n4） 远程调用返回对象时，一律要求进行空指针判断，防止NPE。  \n5） 对于Session中获取的数据，建议NPE检查，避免空指针。  \n6） 级联调用obj.getA().getB().getC()；一连串调用，易产生NPE。 \n<br><span style=\"color:green\">正例</span>：使用JDK8的Optional类来防止NPE问题。 \n11. 【推荐】定义时区分unchecked / checked 异常，避免直接抛出new RuntimeException()，更不允许抛出Exception或者Throwable，应使用有业务含义的自定义异常。推荐业界已定义过的自定义异常，如：DAOException / ServiceException等。 \n12. 【参考】对于公司外的http/api开放接口必须使用“错误码”；而应用内部推荐异常抛出；跨应用间RPC调用优先考虑使用Result方式，封装isSuccess()方法、“错误码”、“错误简短信息”。 \n<br><span style=\"color:orange\">说明</span>：关于RPC方法返回方式使用Result方式的理由：\n <br>1）使用抛异常返回方式，调用方如果没有捕获到就会产生运行时错误。\n 2）如果不加栈信息，只是new自定义异常，加入自己的理解的error message，对于调用端解决问题的帮助不会太多。如果加了栈信息，在频繁调用出错的情况下，数据序列化和传输的性能损耗也是问题。 \n13. 【参考】避免出现重复的代码（Don’t Repeat Yourself），即DRY原则。 \n <br><span style=\"color:orange\">说明</span>：随意复制和粘贴代码，必然会导致代码的重复，在以后需要修改时，需要修改所有的副本，容易遗漏。必要时抽取共性方法，或者抽象公共类，甚至是组件化。 <br><span style=\"color:green\">正例</span>：一个类中有多个public方法，都需要进行数行相同的参数校验操作，这个时候请抽取： \n <pre>private boolean checkParam(DTO dto) {...}</pre>"
  },
  {
    "path": "p3c-gitbook/异常日志/日志规约.md",
    "content": "## (二) 日志规约 \n1. 【强制】应用中不可直接使用日志系统（Log4j、Logback）中的API，而应依赖使用日志框架SLF4J中的API，使用门面模式的日志框架，有利于维护和各个类的日志处理方式统一。 \n<pre>\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nprivate static final Logger logger = LoggerFactory.getLogger(Abc.class);  \n</pre>\n2. 【强制】日志文件推荐至少保存15天，因为有些异常具备以“周”为频次发生的特点。 \n3. 【强制】应用中的扩展日志（如打点、临时监控、访问日志等）命名方式：appName_logType_logName.log。logType:日志类型，推荐分类有stats/monitor/visit等；logName:日志描述。这种命名的好处：通过文件名就可知道日志文件属于什么应用，什么类型，什么目的，也有利于归类查找。 \n<br><span style=\"color:green\">正例</span>：mppserver应用中单独监控时区转换异常，如：                                 \nmppserver_monitor_timeZoneConvert.log \n<br><span style=\"color:orange\">说明</span>：推荐对日志进行分类，如将错误日志和业务日志分开存放，便于开发人员查看，也便于通过日志对系统进行及时监控。 \n4. 【强制】对trace/debug/info级别的日志输出，必须使用条件输出形式或者使用占位符的方式。 \n<br><span style=\"color:orange\">说明</span>：logger.debug(\"Processing trade with id: \" + id + \" and symbol: \" + symbol); 如果日志级别是warn，上述日志不会打印，但是会执行字符串拼接操作，如果symbol是对象，会执行toString()方法，浪费了系统资源，执行了上述操作，最终日志却没有打印。 \n<br><span style=\"color:green\">正例</span>：\n    <pre>（条件） \n      if (logger.isDebugEnabled()) {    \n      logger.debug(\"Processing trade with id: \" + id + \" and symbol: \" + symbol);   \n      }  </pre>     \n<br><span style=\"color:green\">正例</span>：\n    <pre>（占位符） \n          logger.debug(\"Processing trade with id: {} and symbol : {} \", id, symbol);  \n    </pre>\n5. 【强制】避免重复打印日志，浪费磁盘空间，务必在log4j.xml中设置additivity=false。 \n<br><span style=\"color:green\">正例</span>：\n      `<logger name=\"com.taobao.dubbo.config\" additivity=\"false\">`\n6. 【强制】异常信息应该包括两类信息：案发现场信息和异常堆栈信息。如果不处理，那么通过关键字throws往上抛出。 \n<br><span style=\"color:green\">正例</span>：\n<pre>logger.error(各类参数或者对象toString + \"_\" + e.getMessage(), e);</pre> \n7. 【推荐】谨慎地记录日志。生产环境禁止输出debug日志；有选择地输出info日志；如果使用warn来记录刚上线时的业务行为信息，一定要注意日志输出量的问题，避免把服务器磁盘撑爆，并记得及时删除这些观察日志。 <br><span style=\"color:orange\">说明</span>：大量地输出无效日志，不利于系统性能提升，也不利于快速定位错误点。记录日志时请思考：这些日志真的有人看吗？看到这条日志你能做什么？能不能给问题排查带来好处？ \n8. 【推荐】可以使用warn日志级别来记录用户输入参数错误的情况，避免用户投诉时，无所适从。如非必要，请不要在此场景打出error级别，避免频繁报警。\n<br><span style=\"color:orange\">说明</span>：注意日志输出的级别，error级别只记录系统逻辑出错、异常或者重要的错误信息。"
  },
  {
    "path": "p3c-gitbook/本手册专有名词.md",
    "content": "## 附2：本手册专有名词\n1. POJO（Plain Ordinary Java Object）: 在本手册中，POJO专指只有setter / getter / toString的简单类，包括DO/DTO/BO/VO等。 \n2. GAV（GroupId、ArtifactId、Version）: Maven坐标，是用来唯一标识jar包。\n3. OOP（Object Oriented Programming）: 本手册泛指类、对象的编程处理方式。 \n4. ORM（Object Relation Mapping）: 对象关系映射，对象领域模型与底层数据之间的转换，本文泛指iBATIS, mybatis等框架。 \n5. NPE（java.lang.NullPointerException）: 空指针异常。 \n6. SOA（Service-Oriented Architecture）: 面向服务架构，它可以根据需求通过网络对松散耦合的粗粒度应用组件进行分布式部署、组合和使用，有利于提升组件可重用性，可维护性。 \n7. 一方库: 本工程内部子项目模块依赖的库（jar包）。 \n8. 二方库: 公司内部发布到中央仓库，可供公司内部其它应用依赖的库（jar包）。 \n9. 三方库: 公司之外的开源库（jar包）。 \n10. IDE（Integrated Development Environment）: 用于提供程序开发环境的应用程序，一般包括代码编辑器、编译器、调试器和图形用户界面等工具，本《手册》泛指IntelliJ IDEA和eclipse。 "
  },
  {
    "path": "p3c-gitbook/版本历史.md",
    "content": "## 附1：版本历史\n| 版本号 | 更新日期 | 备注 |\n| ------------- |:-------------| :----- |\n| 1.0.0     | 2017.2.9 | 阿里巴巴集团正式对外发布 | \n| 1.0.1      | 2017.2.13      |   1）修正String[]的前后矛盾。2）vm修正成velocity。3）修正countdown描述错误。 |\n| 1.0.2 | 2017.2.20     |    1）去除文底水印。2）数据类型中引用太阳系年龄问题。3）修正关于异常和方法签名的部分描述。4）修正final描述。5）去除Comparator部分描述。  |\n| 1.1.0     | 2017.2.27 | 1）增加前言。2）增加<? extends T>描述和说明。3）增加版本历史。4）增加专有名词解释 | \n| 1.1.1     | 2017.3.31 | 修正页码总数和部分示例。 | \n| 1.2.0     | 2017.5.20 | 1）根据云栖社区的“聚能聊”活动反馈，对手册的页码、排版、描述进行修正。2）增加final的适用场景描述。3）增加关于锁的粒度的说明。4）增加“指定集合大小”的详细说明以及正反例。5）增加卫语句的示例代码。6）明确数据库表示删除概念的字段名为is_deleted  | \n| 1.3.0     | 2017.9.25 | 增加单元测试规约（PDF终极版），阿里开源的IDE代码规约检测插件：[点此下载](https://github.com/alibaba/p3c) 更多及时信息，请关注《阿里巴巴Java开发手册》官方公众号：![QRcode](images/QRcode.jpg)|\n| 1.3.1     | 2017.11.30 | 修正部分描述；采用和P3C开源IDE检测插件相同的Apache2.0协议。 |  \n"
  },
  {
    "path": "p3c-gitbook/编程规约/OOP规范.md",
    "content": "## (四) OOP规约 \n\n1. 【强制】避免通过一个类的对象引用访问此类的静态变量或静态方法，无谓增加编译器解析成本，直接用**类名**来访问即可。 \n2. 【强制】所有的覆写方法，必须加@Override注解。 \n<br><span style=\"color:orange\">说明</span>：getObject()与get0bject()的问题。一个是字母的O，一个是数字的0，加@Override可以准确判断是否覆盖成功。另外，如果在抽象类中对方法签名进行修改，其实现类会马上编译报错。 \n3. 【强制】相同参数类型，相同业务含义，才可以使用Java的可变参数，避免使用Object。 \n<br><span style=\"color:orange\">说明</span>：可变参数必须放置在参数列表的最后。（提倡同学们尽量不用可变参数编程） \n<br><span style=\"color:green\">正例</span>：\n```\npublic User getUsers(String type, Integer... ids) {...} \n```\n4. 【强制】外部正在调用或者二方库依赖的接口，不允许修改方法签名，避免对接口调用方产生影响。接口过时必须加`@Deprecated`注解，并清晰地说明采用的新接口或者新服务是什么。 \n5. 【强制】不能使用过时的类或方法。 \n<br><span style=\"color:orange\">说明</span>：java.net.URLDecoder 中的方法decode(String encodeStr) 这个方法已经过时，应该使用双参数decode(String source, String encode)。接口提供方既然明确是过时接口，那么有义务同时提供新的接口；作为调用方来说，有义务去考证过时方法的新实现是什么。 \n6. 【强制】Object的equals方法容易抛空指针异常，应使用常量或确定有值的对象来调用equals。\n<br><span style=\"color:green\">正例</span>：\"test\".equals(object);\n<br><span style=\"color:red\">反例</span>：object.equals(\"test\"); \n<br><span style=\"color:orange\">说明</span>：推荐使用java.util.Objects#equals（JDK7引入的工具类）\n7. 【强制】所有的相同类型的包装类对象之间值的比较，全部使用equals方法比较。 \n<br><span style=\"color:orange\">说明</span>：对于Integer var = ?  在-128至127范围内的赋值，Integer对象是在IntegerCache.cache产生，会复用已有对象，这个区间内的Integer值可以直接使用==进行判断，但是这个区间之外的所有数据，都会在堆上产生，并不会复用已有对象，这是一个大坑，推荐使用equals方法进行判断。 \n8. 关于基本数据类型与包装数据类型的使用标准如下：\n<br>1） 【强制】所有的POJO类属性必须使用包装数据类型。\n<br>2） 【强制】RPC方法的返回值和参数必须使用包装数据类型。\n<br>3） 【推荐】所有的局部变量使用基本数据类型。\n<br><span style=\"color:orange\">说明</span>：POJO类属性没有初值是提醒使用者在需要使用时，必须自己显式地进行赋值，任何NPE问题，或者入库检查，都由使用者来保证。\n<br><span style=\"color:green\">正例</span>：数据库的查询结果可能是null，因为自动拆箱，用基本数据类型接收有NPE风险。\n<br><span style=\"color:red\">反例</span>：比如显示成交总额涨跌情况，即正负x%，x为基本数据类型，调用的RPC服务，调用不成功时，返回的是默认值，页面显示为0%，这是不合理的，应该显示成中划线。所以包装数据类型的null值，能够表示额外的信息，如：远程调用失败，异常退出。 \n9. 【强制】定义DO/DTO/VO等POJO类时，不要设定任何属性**默认值**。\n<br><span style=\"color:red\">反例</span>：POJO类的gmtCreate默认值为new Date();但是这个属性在数据提取时并没有置入具体值，在更新其它字段时又附带更新了此字段，导致创建时间被修改成当前时间。 \n10. 【强制】序列化类新增属性时，请不要修改serialVersionUID字段，避免反序列失败；如果完全不兼容升级，避免反序列化混乱，那么请修改serialVersionUID值。 \n<br><span style=\"color:orange\">说明</span>：注意serialVersionUID不一致会抛出序列化运行时异常。 \n11. 【强制】构造方法里面禁止加入任何业务逻辑，如果有初始化逻辑，请放在init方法中。 \n12. 【强制】POJO类必须写toString方法。使用IDE中的工具：source> generate toString时，如果继承了另一个POJO类，注意在前面加一下super.toString。 <br><span style=\"color:orange\">说明</span>：在方法执行抛出异常时，可以直接调用POJO的toString()方法打印其属性值，便于排查问题。 \n13. 【推荐】使用索引访问用String的split方法得到的数组时，需做最后一个分隔符后有无内容的检查，否则会有抛IndexOutOfBoundsException的风险。 \n<br><span style=\"color:orange\">说明</span>：\n```\nString str = \"a,b,c,,\";  \nString[] ary = str.split(\",\");  \n// 预期大于3，结果是3 System.out.println(ary.length);\n```\n14. 【推荐】当一个类有多个构造方法，或者多个同名方法，这些方法应该按顺序放置在一起，便于阅读，此条规则优先于第15条规则。 \n15. 【推荐】 类内方法定义的顺序依次是：公有方法或保护方法 > 私有方法 > getter/setter方法。\n<br><span style=\"color:orange\">说明</span>：公有方法是类的调用者和维护者最关心的方法，首屏展示最好；保护方法虽然只是子类关心，也可能是“模板设计模式”下的核心方法；而私有方法外部一般不需要特别关心，是一个黑盒实现；因为承载的信息价值较低，所有Service和DAO的getter/setter方法放在类体最后。 \n16. 【推荐】setter方法中，参数名称与类成员变量名称一致，this.成员名 = 参数名。在getter/setter方法中，不要增加业务逻辑，增加排查问题的难度。\n<br><span style=\"color:red\">反例</span>：\n```\n  public Integer getData() {      \n      if (condition) {  \n        return this.data + 100;  \n      } else { \n        return this.data - 100; \n      }  \n  }\n```\n17. 【推荐】循环体内，字符串的连接方式，使用StringBuilder的append方法进行扩展。\n<br><span style=\"color:orange\">说明</span>：反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象，然后进行append操作，最后通过toString方法返回String对象，造成内存资源浪费。  <br><span style=\"color:red\">反例</span>：\n```\n  String str = \"start\";\n  for (int i = 0; i < 100; i++) {\n      str = str + \"hello\";      \n  }\n```\n18. 【推荐】final可以声明类、成员变量、方法、以及本地变量，下列情况使用final关键字：\n<br>1） 不允许被继承的类，如：String类。\n<br>2） 不允许修改引用的域对象，如：POJO类的域变量。\n<br>3） 不允许被重写的方法，如：POJO类的setter方法。\n<br>4） 不允许运行过程中重新赋值的局部变量。\n<br>5） 避免上下文重复使用一个变量，使用final描述可以强制重新定义一个变量，方便更好地进行重构。 \n19. 【推荐】慎用Object的clone方法来拷贝对象。 \n<br><span style=\"color:orange\">说明</span>：对象的clone方法默认是浅拷贝，若想实现深拷贝需要重写clone方法实现属性对象的拷贝。 \n20. 【推荐】类成员与方法访问控制从严：\n<br>1） 如果不允许外部直接通过new来创建对象，那么构造方法必须是private。\n<br>2） 工具类不允许有public或default构造方法。\n<br>3） 类非static成员变量并且与子类共享，必须是protected。\n<br>4） 类非static成员变量并且仅在本类使用，必须是private。\n<br>5） 类static成员变量如果仅在本类使用，必须是private。\n<br>6） 若是static成员变量，必须考虑是否为final。\n<br>7） 类成员方法只供类内部调用，必须是private。\n<br>8） 类成员方法只对继承类公开，那么限制为protected。 \n<br><span style=\"color:orange\">说明</span>：任何类、方法、参数、变量，严控访问范围。过于宽泛的访问范围，不利于模块解耦。思考：如果是一个private的方法，想删除就删除，可是一个public的service成员方法或成员变量，删除一下，不得手心冒点汗吗？变量像自己的小孩，尽量在自己的视线内，变量作用域太大，无限制的到处跑，那么你会担心的。 "
  },
  {
    "path": "p3c-gitbook/编程规约/代码格式.md",
    "content": "## （三）代码格式\n1. 【强制】大括号的使用约定。如果是大括号内为空，则简洁地写成`{}`即可，不需要换行；如果是非空代码块则：\n<br>1） 左大括号前不换行。\n<br>2） 左大括号后换行。\n<br>3） 右大括号前换行。\n<br>4） 右大括号后还有else等代码则不换行；表示终止的右大括号后必须换行。 \n2. 【强制】 左小括号和字符之间不出现空格；同样，右小括号和字符之间也不出现空格。详见第5条下方正例提示。\n<br><span style=\"color:red\">反例</span>：\n```\nif (空格a == b空格)\n```\n3. 【强制】if/for/while/switch/do等保留字与括号之间都必须加空格。 \n4. 【强制】任何二目、三目运算符的左右两边都需要加一个空格。 \n   <br><span style=\"color:orange\">说明</span>：运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号等。\n5. 【强制】采用4个空格缩进，禁止使用tab字符。 \n   <br><span style=\"color:orange\">说明</span>：\n    如果使用tab缩进，必须设置1个tab为4个空格。IDEA设置tab为4个空格时，请勿勾选`Use tab character`；而在eclipse中，必须勾选`insert spaces for tabs`。 \n   <br><span style=\"color:green\">正例</span>： （涉及1-5点）\n\n          public static void main(String[] args) {\n              // 缩进4个空格\n              String say = \"hello\";\n              // 运算符的左右必须有一个空格\n              int flag = 0;\n              // 关键词if与括号之间必须有一个空格，括号内的f与左括号，0与右括号不需要空格\n              if (flag == 0) {\n                  System.out.println(say);\n              }\n              // 左大括号前加空格且不换行；左大括号后换行\n              if (flag == 1) {\n                  System.out.println(\"world\");\n                  // 右大括号前换行，右大括号后有else，不用换行\n              } else {\n                  System.out.println(\"ok\");\n                  // 在右大括号后直接结束，则必须换行\n              }\n          }\n\n6. 【强制】注释的双斜线与注释内容之间有且仅有一个空格。 \n <br><span style=\"color:green\">正例</span>：\n```\n// 这是示例注释，请注意在双斜线之后有一个空格  \nString ygb = new String(); \n```\n7. 【强制】单行字符数限制不超过120个，超出需要换行，换行时遵循如下原则：\n<br>1）第二行相对第一行缩进4个空格，从第三行开始，不再继续缩进，参考示例。\n<br>2）运算符与下文一起换行。\n<br>3）方法调用的点符号与下文一起换行。\n<br>4） 方法调用时，多个参数，需要换行时，在逗号后进行。\n<br>5） 在括号前不要换行，见反例。\n<br><span style=\"color:green\">正例</span>：\n```\nStringBuffer sb = new StringBuffer();\n     // 超过120个字符的情况下，换行缩进4个空格，点号和方法名称一起换行\n    sb.append(\"zi\").append(\"xin\")...\n                   .append(\"huang\")...\n                   .append(\"huang\")...\n                   .append(\"huang\");\n```\n<br><span style=\"color:red\">反例</span>：\n```\nStringBuffer sb = new StringBuffer();  \n// 超过120个字符的情况下，不要在括号前换行  \nsb.append(\"zi\").append(\"xin\")...append      \n(\"huang\");    \n// 参数很多的方法调用可能超过120个字符，不要在逗号前换行  \nmethod(args1, args2, args3, ... \n, argsX); \n```\n8. 【强制】方法参数在定义和传入时，多个参数逗号后边必须加空格。 \n<br><span style=\"color:green\">正例</span>：下例中实参的\"a\",后边必须要有一个空格。 \n```\nmethod(\"a\", \"b\", \"c\"); \n```\n9. 【强制】IDE的text file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式，不要使用Windows格式。 \n10. 【推荐】没有必要增加若干空格来使某一行的字符与上一行对应位置的字符对齐。 \n<br><span style=\"color:green\">正例</span>： \n```\nint a = 3;  \nlong b = 4L;  \nfloat c = 5F;  \nStringBuffer sb = new StringBuffer();\n```\n<span style=\"color:orange\">说明</span>：增加sb这个变量，如果需要对齐，则给a、b、c都要增加几个空格，在变量比较多的情况下，是非常累赘的事情。 \n11. 【推荐】不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。 \n<br><span style=\"color:orange\">说明</span>：没有必要插入**多个空行**进行隔开。 "
  },
  {
    "path": "p3c-gitbook/编程规约/命名风格.md",
    "content": "# 一、编程规约\n##（一）命名风格\n\n1. 【强制】代码中的命名均不能以<strong>下划线或美元符号</strong>开始，也不能以<strong>下划线或美元符号</strong>结束。\n  <br><span style=\"color:red\">反例</span>：`_name / __name / $name / name_ / name$ / name__`\n2. 【强制】代码中的命名严禁使用拼音与英文混合的方式，更不允许直接使用中文的方式。 \n  <br><span style=\"color:orange\">说明</span>：正确的英文拼写和语法可以让阅读者易于理解，避免歧义。注意，即使纯拼音命名方式也要避免采用。 \n  <br><span style=\"color:green\">正例</span>：alibaba / taobao / youku / hangzhou 等国际通用的名称，可视同英文。 \n  <br><span style=\"color:red\">反例</span>：DaZhePromotion [打折] / getPingfenByName() [评分] / int 某变量 = 3 \n3. 【强制】类名使用`UpperCamelCase`风格，但以下情形例外：DO / BO / DTO / VO / AO / PO等。 \n <br><span style=\"color:green\">正例</span>：MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion \n <br><span style=\"color:red\">反例</span>：macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion \n4. 【强制】方法名、参数名、成员变量、局部变量都统一使用`lowerCamelCase`风格，必须遵从驼峰形式。 \n<br><span style=\"color:green\">正例</span>： localValue / getHttpMessage() / inputUserId \n5. 【强制】常量命名全部大写，单词间用下划线隔开，力求语义表达完整清楚，不要嫌名字长。 \n<br><span style=\"color:green\">正例</span>：MAX_STOCK_COUNT \n<br><span style=\"color:red\">反例</span>：MAX_COUNT \n6. 【强制】抽象类命名使用Abstract或Base开头；异常类命名使用Exception结尾；测试类命名以它要测试的类名开始，以Test结尾。 \n7. 【强制】类型与中括号紧挨相连来定义数组。 \n <br><span style=\"color:green\">正例</span>：定义整形数组<code>int[] arrayDemo;</code> \n <br><span style=\"color:red\">反例</span>：在main参数中，使用<code>String args[]</code>来定义。 \n8. 【强制】POJO类中布尔类型的变量，都不要加is前缀，否则部分框架解析会引起序列化错误。 \n <br><span style=\"color:red\">反例</span>：定义为基本数据类型<code>Boolean isDeleted；</code>的属性，它的方法也是<code>isDeleted()</code>，RPC框架在反向解析的时候，“误以为”对应的属性名称是deleted，导致属性获取不到，进而抛出异常。\n9. 【强制】包名统一使用小写，点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式，但是类名如果有复数含义，类名可以使用复数形式。 \n <br><span style=\"color:green\">正例</span>：应用工具类包名为com.alibaba.ai.util、类名为MessageUtils（此规则参考spring的框架结构） \n10. 【强制】杜绝完全不规范的缩写，避免望文不知义。 \n <br><span style=\"color:red\">反例</span>：AbstractClass“缩写”命名成AbsClass；condition“缩写”命名成 condi，此类随意缩写严重降低了代码的可阅读性。 \n11. 【推荐】为了达到代码自解释的目标，任何自定义编程元素在命名时，使用尽量完整的单词组合来表达其意。 \n<br><span style=\"color:green\">正例</span>：从远程仓库拉取代码的类命名为PullCodeFromRemoteRepository。 \n<br><span style=\"color:red\">反例</span>：变量int a; 的随意命名方式。 \n12. 【推荐】如果模块、接口、类、方法使用了设计模式，在命名时体现出具体模式。 \n<br><span style=\"color:orange\">说明</span>：将设计模式体现在名字中，有利于阅读者快速理解架构设计理念。 \n<br><span style=\"color:green\">正例</span>：\n```\npublic class OrderFactory;\npublic class LoginProxy;\npublic class ResourceObserver; \n```\n13. 【推荐】接口类中的方法和属性不要加任何修饰符号（public 也不要加），保持代码的简洁性，并加上有效的Javadoc注释。尽量不要在接口里定义变量，如果一定要定义变量，肯定是与接口方法相关，并且是整个应用的基础常量。 \n<br><span style=\"color:green\">正例</span>：接口方法签名void f(); 接口基础常量String COMPANY = \"alibaba\"; \n<br><span style=\"color:red\">反例</span>：接口方法定义public abstract void f(); \n<br><span style=\"color:orange\">说明</span>：JDK8中接口允许有默认实现，那么这个default方法，是对所有实现类都有价值的默认实现。 \n14. 接口和实现类的命名有两套规则：  \n   1）【强制】对于Service和DAO类，基于SOA的理念，暴露出来的服务一定是接口，内部的实现类用Impl的后缀与接口区别。 \n   <br><span style=\"color:green\">正例</span>：CacheServiceImpl实现CacheService接口。<br>\n   2） 【推荐】 如果是形容能力的接口名称，取对应的形容词为接口名（通常是–able的形式）。\n   <br><span style=\"color:green\">正例</span>：AbstractTranslator实现 Translatable。 \n15. 【参考】枚举类名建议带上Enum后缀，枚举成员名称需要全大写，单词间用下划线隔开。 \n<br><span style=\"color:orange\">说明</span>：枚举其实就是特殊的常量类，且构造方法被默认强制是私有。 \n<br><span style=\"color:green\">正例</span>：枚举名字为ProcessStatusEnum的成员名称：SUCCESS / UNKNOWN_REASON。 \n16. 【参考】各层命名规约：  \n  A) Service/DAO层方法命名规约<br>\n   1） 获取单个对象的方法用get作前缀。\n   <br>2） 获取多个对象的方法用list作前缀。\n   <br>3） 获取统计值的方法用count作前缀。    \n   4） 插入的方法用save/insert作前缀。    \n   5） 删除的方法用remove/delete作前缀。    \n   6） 修改的方法用update作前缀。 \n  <br>B) 领域模型命名规约 <br>\n   1） 数据对象：xxxDO，xxx即为数据表名。    \n   2） 数据传输对象：xxxDTO，xxx为业务领域相关的名称。    \n   3） 展示对象：xxxVO，xxx一般为网页名称。    \n   4） POJO是DO/DTO/BO/VO的统称，禁止命名成xxxPOJO。 "
  },
  {
    "path": "p3c-gitbook/编程规约/常量定义.md",
    "content": "## （二）常量定义\n\n1. 【强制】不允许任何魔法值（即未经预先定义的常量）直接出现在代码中。\n<br><span style=\"color:red\">反例</span>：\n```\nString key = \"Id#taobao_\" + tradeId;       \ncache.put(key, value); \n```\n2. 【强制】long或者Long初始赋值时，使用大写的L，不能是小写的l，小写容易跟数字1混淆，造成误解。 \n<br><span style=\"color:orange\">说明</span>：<pre>Long a = 2l;</pre> 写的是数字的`21`，还是Long型的`2`? \n3. 【推荐】不要使用一个常量类维护所有常量，按常量功能进行归类，分开维护。 \n<br><span style=\"color:orange\">说明</span>：大而全的常量类，非得使用查找功能才能定位到修改的常量，不利于理解和维护。 \n<br><span style=\"color:green\">正例</span>：缓存相关常量放在类CacheConsts下；系统配置相关常量放在类ConfigConsts下。 \n4. 【推荐】常量的复用层次有五层：跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。  \n1） 跨应用共享常量：放置在二方库中，通常是client.jar中的constant目录下。\n2） 应用内共享常量：放置在一方库中，通常是子模块中的constant目录下。\n<br><span style=\"color:red\">反例</span>：易懂变量也要统一定义成应用内共享常量，两位攻城师在两个类中分别定义了表示“是”的变量：\n```\n    类A中：public static final String YES = \"yes\";\n    类B中：public static final String YES = \"y\";\n    A.YES.equals(B.YES) 预期是true，但实际返回为false，导致线上问题。\n```\n3） 子工程内部共享常量：即在当前子工程的constant目录下。  \n4） 包内共享常量：即在当前包下单独的constant目录下。  \n5） 类内共享常量：直接在类内部private static final定义。 \n5. 【推荐】如果变量值仅在一个固定范围内变化用enum类型来定义。 说明：如果存在名称之外的延伸属性使用enum类型，下面正例中的数字就是延伸信息，表示一年中的第几个季节。 \n <br><span style=\"color:green\">正例</span>： \n```\n  public enum SeasonEnum {   \n          SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);\n          int seq; \n          SeasonEnum(int seq){         \n              this.seq = seq;     \n          } \n  } \n```"
  },
  {
    "path": "p3c-gitbook/编程规约/并发处理.md",
    "content": "## (六) 并发处理 \n1. 【强制】获取单例对象需要保证线程安全，其中的方法也要保证线程安全。 \n<br><span style=\"color:orange\">说明</span>：资源驱动类、工具类、单例工厂类都需要注意。 \n2. 【强制】创建线程或线程池时请指定有意义的线程名称，方便出错时回溯。 \n<br><span style=\"color:green\">正例</span>：\n```\n    public class TimerTaskThread extends Thread {      \n        public TimerTaskThread() {      \n              super.setName(\"TimerTaskThread\");   \n              ... \n        }\n    }\n```  \n3. 【强制】线程资源必须通过线程池提供，不允许在应用中自行显式创建线程。 \n<br><span style=\"color:orange\">说明</span>：使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销，解决资源不足的问题。如果不使用线程池，有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。 \n4. 【强制】线程池不允许使用Executors去创建，而是通过ThreadPoolExecutor的方式，这样的处理方式让写的同学更加明确线程池的运行规则，规避资源耗尽的风险。 \n<br><span style=\"color:orange\">说明</span>：Executors返回的线程池对象的弊端如下：\n1）`FixedThreadPool`和`SingleThreadPool`:   允许的请求队列长度为Integer.MAX_VALUE，可能会堆积大量的请求，从而导致OOM。\n2）`CachedThreadPool`和`ScheduledThreadPool`:   允许的创建线程数量为Integer.MAX_VALUE，可能会创建大量的线程，从而导致OOM。\n5. 【强制】SimpleDateFormat 是线程不安全的类，一般不要定义为static变量，如果定义为static，必须加锁，或者使用DateUtils工具类。 \n<br><span style=\"color:green\">正例</span>：注意线程安全，使用`DateUtils`。亦推荐如下处理： \n```\nprivate static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {        \n    Override        \n    protected DateFormat initialValue() {         \n        return new SimpleDateFormat(\"yyyy-MM-dd\");        \n    }    \n};\n```   \n<span style=\"color:orange\">说明</span>：如果是JDK8的应用，可以使用`Instant`代替`Date`，`LocalDateTime`代替`Calendar`，`DateTimeFormatter`代替`SimpleDateFormat`，官方给出的解释：\n>simple beautiful strong immutable thread-safe。\n6. 【强制】高并发时，同步调用应该去考量锁的性能损耗。能用无锁数据结构，就不要用锁；能锁区块，就不要锁整个方法体；能用对象锁，就不要用类锁。 <br><span style=\"color:orange\">说明</span>：尽可能使加锁的代码块工作量尽可能的小，避免在锁代码块中调用RPC方法。 \n7. 【强制】对多个资源、数据库表、对象同时加锁时，需要保持一致的加锁顺序，否则可能会造成死锁。 <br><span style=\"color:orange\">说明</span>：线程一需要对表A、B、C依次全部加锁后才可以进行更新操作，那么线程二的加锁顺序也必须是A、B、C，否则可能出现死锁。 \n8. 【强制】并发修改同一记录时，避免更新丢失，需要加锁。要么在应用层加锁，要么在缓存加锁，要么在数据库层使用乐观锁，使用version作为更新依据。 <br><span style=\"color:orange\">说明</span>：如果每次访问冲突概率小于20%，推荐使用乐观锁，否则使用悲观锁。乐观锁的重试次数不得小于3次。 \n9. 【强制】多线程并行处理定时任务时，Timer运行多个TimeTask时，只要其中之一没有捕获抛出的异常，其它任务便会自动终止运行，使用`ScheduledExecutorService`则没有这个问题。 \n10. 【推荐】使用`CountDownLatch`进行异步转同步操作，每个线程退出前必须调用countDown方法，线程执行代码注意catch异常，确保countDown方法被执行到，避免主线程无法执行至await方法，直到超时才返回结果。 <br><span style=\"color:orange\">说明</span>：注意，子线程抛出异常堆栈，不能在主线程try-catch到。 \n11. 【推荐】避免Random实例被多线程使用，虽然共享该实例是线程安全的，但会因竞争同一seed 导致的性能下降。 \n<br><span style=\"color:orange\">说明</span>：Random实例包括java.util.Random 的实例或者 Math.random()的方式。 \n<br><span style=\"color:green\">正例</span>：在JDK7之后，可以直接使用API ThreadLocalRandom，而在 JDK7之前，需要编码保证每个线程持有一个实例。 \n12. 【推荐】在并发场景下，通过双重检查锁（double-checked locking）实现延迟初始化的优化问题隐患(可参考 The \"Double-Checked Locking is Broken\" Declaration)，推荐解决方案中较为简单一种（适用于JDK5及以上版本），将目标属性声明为 volatile型。 \n<br><span style=\"color:red\">反例</span>：\n```\n  class Singleton {   \n        private Helper helper = null;  \n        public Helper getHelper() {  \n          if (helper == null) \n          synchronized(this) {      \n            if (helper == null)        \n            helper = new Helper();    \n          }      \n          return helper;  \n        }  \n        // other methods and fields...  \n  }\n```\n13. 【参考】volatile解决多线程内存不可见问题。对于一写多读，是可以解决变量同步问题，但是如果多写，同样无法解决线程安全问题。如果是count++操作，使用如下类实现：\n```\nAtomicInteger count = new AtomicInteger(); \ncount.addAndGet(1); \n```\n如果是JDK8，推荐使用`LongAdder`对象，比`AtomicLong`性能更好（减少乐观锁的重试次数）。\n14. 【参考】 HashMap在容量不够进行resize时由于高并发可能出现死链，导致CPU飙升，在开发过程中可以使用其它数据结构或加锁来规避此风险。 \n15. 【参考】`ThreadLocal`无法解决共享对象的更新问题，`ThreadLocal`对象建议使用static修饰。这个变量是针对一个线程内所有操作共享的，所以设置为静态变量，所有此类实例共享此静态变量 ，也就是说在类第一次被使用时装载，只分配一块存储空间，所有此类的对象(只要是这个线程内定义的)都可以操控这个变量。 "
  },
  {
    "path": "p3c-gitbook/编程规约/控制语句.md",
    "content": "## (七) 控制语句 \n1. 【强制】在一个switch块内，每个case要么通过break/return等来终止，要么注释说明程序将继续执行到哪一个case为止；在一个switch块内，都必须包含一个default语句并且放在最后，即使空代码。 \n2. 【强制】在if/else/for/while/do语句中必须使用大括号。即使只有一行代码，避免采用单行的编码方式：\n<pre>if (condition) statements;</pre>\n3. 【强制】在高并发场景中，避免使用”等于”判断作为中断或退出的条件。 \n<br><span style=\"color:orange\">说明</span>：如果并发控制没有处理好，容易产生等值判断被“击穿”的情况，使用大于或小于的区间判断条件来代替。  \n<br><span style=\"color:red\">反例</span>：判断剩余奖品数量等于0时，终止发放奖品，但因为并发处理错误导致奖品数量瞬间变成了负数，这样的话，活动无法终止。 \n4. 【推荐】表达异常的分支时，少用if-else方式，这种方式可以改写成： \n```\n    if (condition) {              \n      ...              \n      return obj;    \n    }   \n    // 接着写else的业务逻辑代码; \n```\n<br><span style=\"color:orange\">说明</span>：如果非得使用if()...else if()...else...方式表达逻辑，【强制】避免后续代码维护困难，请勿超过3层。\n<br><span style=\"color:green\">正例</span>：超过3层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现，其中卫语句示例如下： \n```\npublic void today() {      \n  if (isBusy()) {   \n      System.out.println(“change time.”);            \n      return; \n  }       \n  if (isFree()) {  \n      System.out.println(“go to travel.”);             \n      return;     \n  }  \n  System.out.println(“stay at home to learn Alibaba Java Coding Guidelines.”);      \n  return; \n  } \n```\n5. 【推荐】除常用方法（如getXxx/isXxx）等外，不要在条件判断中执行其它复杂的语句，将复杂逻辑判断的结果赋值给一个有意义的布尔变量名，以提高可读性。 \n<br><span style=\"color:orange\">说明</span>：很多if语句内的逻辑相当复杂，阅读者需要分析条件表达式的最终结果，才能明确什么样的条件执行什么样的语句，那么，如果阅读者分析逻辑表达式错误呢？ <br><span style=\"color:green\">正例</span>： \n```\n// 伪代码如下 final boolean existed = (file.open(fileName, \"w\") != null) && (...) || (...); \nif (existed) {    \n   ... \n}  \n```  \n<span style=\"color:red\">反例</span>：\n```\nif ((file.open(fileName, \"w\") != null) && (...) || (...)) {     \n  ... \n}\n```\n6. 【推荐】循环体中的语句要考量性能，以下操作尽量移至循环体外处理，如定义对象、变量、获取数据库连接，进行不必要的try-catch操作（这个try-catch是否可以移至循环体外）。 \n7. 【推荐】避免采用取反逻辑运算符。 \n<br><span style=\"color:orange\">说明</span>：取反逻辑不利于快速理解，并且取反逻辑写法必然存在对应的正向逻辑写法。 \n<br><span style=\"color:green\">正例</span>：使用if (x < 628) 来表达 x 小于628。\n<br><span style=\"color:red\">反例</span>：使用if (!(x >= 628)) 来表达 x 小于628。\n8. 【推荐】接口入参保护，这种场景常见的是用作批量操作的接口。 \n9. 【参考】下列情形，需要进行参数校验：  \n1） 调用频次低的方法。  \n2） 执行时间开销很大的方法。此情形中，参数校验时间几乎可以忽略不计，但如果因为参数错误导致中间执行回退，或者错误，那得不偿失。  \n3） 需要极高稳定性和可用性的方法。  \n4） 对外提供的开放接口，不管是RPC/API/HTTP接口。  \n5） 敏感权限入口。 \n10. 【参考】下列情形，不需要进行参数校验：\n<br>1） 极有可能被循环调用的方法。但在方法说明里必须注明外部参数检查要求。\n<br>2） 底层调用频度比较高的方法。毕竟是像纯净水过滤的最后一道，参数错误不太可能到底层才会暴露问题。一般DAO层与Service层都在同一个应用中，部署在同一台服务器中，所以DAO的参数校验，可以省略。\n<br>3） 被声明成private只会被自己代码所调用的方法，如果能够确定调用方法的代码传入参数已经做过检查或者肯定不会有问题，此时可以不校验参数。"
  },
  {
    "path": "p3c-gitbook/编程规约/注释规约.md",
    "content": "## (八) 注释规约\n\n1. 【强制】类、类属性、类方法的注释必须使用Javadoc规范，使用/**内容*/格式，不得使用// xxx方式。 \n<br><span style=\"color:orange\">说明</span>：在IDE编辑窗口中，Javadoc方式会提示相关注释，生成Javadoc可以正确输出相应注释；在IDE中，工程调用方法时，不进入方法即可悬浮提示方法、参数、返回值的意义，提高阅读效率。 \n2. 【强制】所有的抽象方法（包括接口中的方法）必须要用Javadoc注释、除了返回值、参数、异常说明外，还必须指出该方法做什么事情，实现什么功能。 \n<br><span style=\"color:orange\">说明</span>：对子类的实现要求，或者调用注意事项，请一并说明。 \n3. 【强制】所有的类都必须添加创建者和创建日期。 \n4. 【强制】方法内部单行注释，在被注释语句上方另起一行，使用`//`注释。方法内部多行注释使用`/* */`注释，注意与代码对齐。 \n5. 【强制】所有的枚举类型字段必须要有注释，说明每个数据项的用途。 \n6. 【推荐】与其“半吊子”英文来注释，不如用中文注释把问题说清楚。专有名词与关键字保持英文原文即可。\n <br><span style=\"color:red\">反例</span>：“TCP连接超时”解释成“传输控制协议连接超时”，理解反而费脑筋。 \n7. 【推荐】代码修改的同时，注释也要进行相应的修改，尤其是参数、返回值、异常、核心逻辑等的修改。 \n<br><span style=\"color:orange\">说明</span>：代码与注释更新不同步，就像路网与导航软件更新不同步一样，如果导航软件严重滞后，就失去了导航的意义。 \n8. 【参考】谨慎注释掉代码。在上方详细说明<，而不是简单地注释掉。如果无用，则删除。 \n<br><span style=\"color:orange\">说明</span>：代码被注释掉有两种可能性：\n1）后续会恢复此段代码逻辑。\n2）永久不用。前者如果没有备注信息，难以知晓注释动机。后者建议直接删掉（代码仓库保存了历史代码）。 \n9. 【参考】对于注释的要求：第一、能够准确反应设计思想和代码逻辑；第二、能够描述业务含义，使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者形同\n天书，注释是给自己看的，即使隔很长时间，也能清晰理解当时的思路；注释也是给继任者看的，使其能够快速接替自己的工作。 \n10. 【参考】好的命名、代码结构是自解释的，注释力求精简准确、表达到位。避免出现注释的一个极端：过多过滥的注释，代码的逻辑一旦修改，修改注释是相当大的负担。 \n<br><span style=\"color:red\">反例</span>：\n ```\n // put elephant into fridge  \n put(elephant, fridge);      \n 方法名put，加上两个有意义的变量名elephant和fridge，已经说明了这是在干什么，语义清晰的代码不需要额外的注释。 \n ```\n11. 【参考】特殊注释标记，请注明标记人与标记时间。注意及时处理这些标记，通过标记扫描，经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。  \n1） 待办事宜（**TODO**）:（ 标记人，标记时间，[预计处理时间]）    表示需要实现，但目前还未实现的功能。这实际上是一个Javadoc的标签，目前的Javadoc还没有实现，但已经被广泛使用。只能应用于类，接口和方法（因为它是一个Javadoc标签）。  \n2） 错误，不能工作（**FIXME**）:（标记人，标记时间，[预计处理时间]）    在注释中用FIXME标记某代码是错误的，而且不能工作，需要及时纠正的情况。 "
  },
  {
    "path": "p3c-gitbook/编程规约/集合处理.md",
    "content": "## (五) 集合处理 \n1. 【强制】关于`hashCode`和`equals`的处理，遵循如下规则： \n<br>1） 只要重写`equals`，就必须重写`hashCode`。 \n<br>2） 因为Set存储的是不重复的对象，依据`hashCode`和`equals`进行判断，所以Set存储的对象必须重写这两个方法。 \n<br>3） 如果自定义对象作为Map的键，那么必须重写`hashCode`和`equals`。 \n<br><span style=\"color:orange\">说明</span>：String重写了hashCode和equals方法，所以我们可以非常愉快地使用String对象作为key来使用。 \n2. 【强制】 ArrayList的subList结果不可强转成ArrayList，否则会抛出ClassCastException异常，即java.util.RandomAccessSubList cannot be cast to java.util.ArrayList. \n<br><span style=\"color:orange\">说明</span>：subList 返回的是 ArrayList 的内部类 SubList，并不是 ArrayList ，而是 ArrayList 的一个视图，对于SubList子列表的所有操作最终会反映到原列表上。 \n3. 【强制】在subList场景中，**高度注意**对原集合元素个数的修改，会导致子列表的遍历、增加、删除均会产生ConcurrentModificationException 异常。 \n4. 【强制】使用集合转数组的方法，必须使用集合的toArray(T[] array)，传入的是类型完全一样的数组，大小就是`list.size()`。 \n<br><span style=\"color:orange\">说明</span>：使用toArray带参方法，入参分配的数组空间不够大时，toArray方法内部将重新分配内存空间，并返回新数组地址；如果数组元素个数大于实际所需，下标为[ list.size() ]的数组元素将被置为null，其它数组元素保持原值，因此最好将方法入参数组大小定义与集合元素个数一致。 \n<br><span style=\"color:green\">正例</span>： \n```\n  List<String> list = new ArrayList<String>(2);      \n  list.add(\"guan\");     \n  list.add(\"bao\");       \n  String[] array = new String[list.size()];      \n  array = list.toArray(array);\n```\n<span style=\"color:red\">反例</span>：直接使用toArray无参方法存在问题，此方法返回值只能是Object[]类，若强转其它类型数组将出现ClassCastException错误。\n5. 【强制】使用工具类Arrays.asList()把数组转换成集合时，不能使用其修改集合相关的方法，它的add/remove/clear方法会抛出UnsupportedOperationException异常。 \n<br><span style=\"color:orange\">说明</span>：asList的返回对象是一个Arrays内部类，并没有实现集合的修改方法。Arrays.asList体现的是适配器模式，只是转换接口，后台的数据仍是数组。\n```\nString[] str = new String[] { \"you\", \"wu\" };     \nList list = Arrays.asList(str); \n```\n第一种情况：list.add(\"yangguanbao\"); 运行时异常。\n<br>第二种情况：str[0] = \"gujin\"; 那么list.get(0)也会随之修改。\n6. 【强制】泛型通配符`<? extends T>`来接收返回的数据，此写法的泛型集合不能使用add方法，而`<? super T>`不能使用get方法，作为接口调用赋值时易出错。 \n<br><span style=\"color:orange\">说明</span>：扩展说一下PECS(Producer Extends Consumer Super)原则：第一、频繁往外读取内容的，适合用<? extends T>。第二、经常往里插入的，适合用`<? super T>`。 \n7. 【强制】不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式，如果并发操作，需要对Iterator对象加锁。 \n<br><span style=\"color:green\">正例</span>： \n```\n    Iterator<String> iterator = list.iterator();  while (iterator.hasNext()) {          \n          String item = iterator.next();                  \n                if (删除元素的条件) {                   \n                        iterator.remove();                 \n                }      \n    }\n```\n<span style=\"color:red\">反例</span>：\n ```\n    List<String> list = new ArrayList<String>();      \n    list.add(\"1\");      \n    list.add(\"2\");      \n    for (String item : list) {        \n        if (\"1\".equals(item)) {          \n              list.remove(item);         \n          }   \n    }\n```\n<span style=\"color:orange\">说明</span>：以上代码的执行结果肯定会出乎大家的意料，那么试一下把“1”换成“2”，会是同样的结果吗？\n8. 【强制】 在JDK7版本及以上，`Comparator`要满足如下三个条件，不然`Arrays.sort`，`Collections.sort`会报IllegalArgumentException异常。\n<br><span style=\"color:orange\">说明</span>：三个条件如下：\n<br>1） x，y的比较结果和y，x的比较结果相反。\n<br>2） x>y，y>z，则x>z。 \n<br>3） x=y，则x，z比较结果和y，z比较结果相同。 \n<br><span style=\"color:red\">反例</span>：下例中没有处理相等的情况，实际使用中可能会出现异常：\n```\n    new Comparator<Student>() {           \n          @Override          \n          public int compare(Student o1, Student o2) {              \n            return o1.getId() > o2.getId() ? 1 : -1;       \n          }  \n    };  \n```\n9. 【推荐】集合初始化时，指定集合初始值大小。 \n<br><span style=\"color:orange\">说明</span>：HashMap使用HashMap(int initialCapacity) 初始化， \n<br><span style=\"color:green\">正例</span>：initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子（即loader factor）默认为0.75，如果暂时无法确定初始值大小，请设置为16（即默认值）。 <br><span style=\"color:red\">反例</span>：HashMap需要放置1024个元素，由于没有设置容量初始大小，随着元素不断增加，容量7次被迫扩大，resize需要重建hash表，严重影响性能。 \n10. 【推荐】使用entrySet遍历Map类集合KV，而不是keySet方式进行遍历。 \n<br><span style=\"color:orange\">说明</span>：keySet其实是遍历了2次，一次是转为Iterator对象，另一次是从hashMap中取出key所对应的value。而entrySet只是遍历了一次就把key和value都放到了entry中，效率更高。如果是JDK8，使用Map.forEach方法。 \n<br><span style=\"color:green\">正例</span>：values()返回的是V值集合，是一个list集合对象；keySet()返回的是K值集合，是一个Set集合对象；entrySet()返回的是K-V值组合集合。 \n11. 【推荐】高度注意Map类集合K/V能不能存储null值的情况，如下表格：\n\n        | 集合类            | Key          | Value        | Super       | 说明                   |\n        |-------------------|--------------|--------------|-------------|------------------------|\n        | Hashtable         | 不允许为null | 不允许为null | Dictionary  | 线程安全               |\n        | ConcurrentHashMap | 不允许为null | 不允许为null | AbstractMap | 锁分段技术（JDK8:CAS）  |\n        | TreeMap           | 不允许为null | 允许为null   | AbstractMap | 线程不安全             |\n        | HashMap           | 允许为null   | 允许为null   | AbstractMap | 线程不安全             |\n\n    <span style=\"color:red\">反例</span>： 由于HashMap的干扰，很多人认为ConcurrentHashMap是可以置入null值，而事实上，存储null值时会抛出NPE异常。\n12. 【参考】合理利用好集合的有序性(sort)和稳定性(order)，避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。 \n<br><span style=\"color:orange\">说明</span>：有序性是指遍历的结果是按某种比较规则依次排列的。稳定性指集合每次遍历的元素次序是一定的。如：ArrayList是order/unsort；HashMap是unorder/unsort；TreeSet是order/sort。 \n13. 【参考】利用Set元素唯一的特性，可以快速对一个集合进行去重操作，避免使用List的contains方法进行遍历、对比、去重操作。 \n"
  },
  {
    "path": "p3c-pmd/.gitignore",
    "content": "# reference to https://github.com/github/gitignore\n\ntestdata/\n# Java gitignore #\n.class\n.log\n\n# Package Files #\n\n*.war\n*.ear\n\n#hsf files\nconfiguration\n\n# maven gitignore#\ntarget/**\n\n.svn/\n\n# intelliJ.gitignore #\n*.iml\n*.ipr\n*.iws\n*.bat\n\n# Eclipse git ignore#\n*.pydevproject\n.project\n.metadata\nbin/**\n*/bin/**\ntmp/**\ntmp/**/*\nconfiguration/**\n*.tmp\n*.bak\n*.orig\n*.swp\n*~.nib\n.classpath\n.settings/\n.loadpath\n.fileTable*\n.cache\n\n# External tool builders\n.externalToolBuilders/\n\n# Locally stored \"Eclipse launch configurations\"\n*.launch\n\n# CDT-specific\n.cproject\n\n# PDT-specific\n.buildpath\n\n#log\n*.log\n*.log.*\n\n# Windows Thumbs.db\n*.db\n\n# OSX\n.DS_Store\n\n# sass gitignore#\n.sass-cache\n.idea\n.vscode\n\n# tcc_coverage\ncoverage.ec\n\n\n\nconfig.client.*\n\ntemp/\n*.pid\n*.orig\n\nhsf.configuration/\n\n# code coverage report\n*.ec\n\n#hsf test\n*.instance\n/target/\n"
  },
  {
    "path": "p3c-pmd/README.md",
    "content": "# P3C-PMD\n\n## <font color=\"green\">Build requirements</font>\n- JDK 1.7+\n- Maven 3\n\n## <font color=\"green\">Use as dependency</font>\n\n### <font color=\"green\">Maven</font>\n```xml\n<dependency>\n    <groupId>com.alibaba.p3c</groupId>\n    <artifactId>p3c-pmd</artifactId>\n    <version>2.1.1</version>\n</dependency>\n```\n### <font color=\"green\">Gradle</font>\n```groovy\ncompile 'com.alibaba.p3c:p3c-pmd:2.1.1'\n```\n\n## <font color=\"green\">Rules</font>\n\nP3C-PMD implements 54 rules involved in *Alibaba Java Coding Guidelines*, based on PMD ([https://github.com/pmd/pmd](https://github.com/pmd/pmd)).\n\n### <font color=\"green\">Concurrency</font>\n* 1 ``[Mandatory]`` Customized ThreadLocal variables must be recycled, especially when using thread pools in which threads are often reused. Otherwise, it may affect subsequent business logic and cause unexpected problems such as memory leak.\n* 2 ``[Mandatory]`` A meaningful thread name is helpful to trace the error information, so assign a name when creating threads or thread pools.  \nPositive example:\n\n    ```java\n    public class TimerTaskThread extends Thread {\n        public TimerTaskThread(){\n            super.setName(\"TimerTaskThread\"); … }\n    ```\n* 3 ``[Mandatory]`` Threads should be provided by thread pools. Explicitly creating threads is not allowed. \nNote: Using thread pool can reduce the time of creating and destroying thread and save system resource. If we do not use thread pools, lots of similar threads will be created which lead to \"running out of memory\" or over-switching problems.\n* 4 ``[Mandatory]`` A thread pool should be created by ThreadPoolExecutor rather than Executors. These would make the parameters of the thread pool understandable. It would also reduce the risk of running out of system resources.\nNote: Below are the problems created by usage of Executors for thread pool creation:  \n    1. FixedThreadPool and SingleThreadPool:\n         Maximum request queue size Integer.MAX_VALUE. A large number of requests might cause OOM.\n    2. CachedThreadPool and ScheduledThreadPool:  \n        The number of threads which are allowed to be created is Integer.MAX_VALUE. Creating too many threads might lead to OOM.\n* 5 ``[Mandatory]`` SimpleDataFormat is unsafe, do not define it as a static variable. If you have to, lock or Apache DateUtils class must be used.\nPositive example: Pay attention to thread-safety when using DateUtils. It is recommended to use below:\n\n    ```java\n    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {  \n        @Override  \n        protected DateFormat initialValue() {  \n            return new SimpleDateFormat(\"yyyy-MM-dd\");  \n        }  \n    };  \n    ```\n    Note: In JDK8, Instant can be used to replace Date; likewise Calendar is replaced by LocalDateTime, and SimpleDateFormatter is replaced by DateTimeFormatter.\n* 6 ``[Mandatory]`` Run multiple TimeTask by using ScheduledExecutorService rather than Timer, because Timer will kill all running threads in case of failure to catch exceptions.\n* 7 ``[Recommended]`` When using CountDownLatch to convert asynchronous operations to synchronous ones, each thread must call countdown method before quitting. Make sure to catch any exception during thread running, to let countdown method be executed. If main thread cannot reach await method, program will return until timeout.\nNote: Be careful, exception thrown by a child thread cannot be caught by main thread.\n* 8 ``[Recommended]`` Avoid using Random instance by multiple threads. Although it is thread-safe, competition on the same seed will damage performance.\nNote: Random instance includes instances of java.util.Random and Math.random().  \nPositive example:  \nAfter JDK7, ThreadLocalRandom API can be used directly. But before JDK7, instance needs to be created in each thread.\n\n### <font color=\"green\">Collection</font>\n\n* 1 ``[Mandatory]`` Do not cast subList in class ArrayList, otherwise ClassCastException will be thrown: java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.  \nNote: subList of ArrayList is an inner class, which is a view of ArrayList. All operations on the Sublist will affect the original list finally.\n* 2 ``[Mandatory]`` When using subList, be careful while modifying the size of original list. It might cause ConcurrentModificationException when performing traversing, adding or deleting on the subList.\n* 3 ``[Mandatory]`` Use toArray(T[] array) to convert list to array. The input array type should be the same with the list whose size is list.size().\nCounter example: Do not use toArray method without arguments. Since the return type is Object[], ClassCastException will be thrown when casting it to a different array type.\nPositive example:\n\n    ```java\n        List<String> list = new ArrayList<String>(2);\n        list.add(\"guan\");\n        list.add(\"bao\");        \n        String[] array = new String[list.size()];\n        array = list.toArray(array);\n    ```\nNote: When using toArray method with arguments, if input array size is not large enough, the method will re-assign the size internally, and then return the address of new array. If the size is larger than needed, the value of index[list.size()] will be set to null while other values remain the same. Defining an input with the same size of the list is recommended.\n* 4 ``[Mandatory]`` Do not use methods which will modify the list after using Arrays.asList to convert array to list, otherwise methods like add/remove/clear will throw UnsupportedOperationException.\nNote: The result of asList is the inner class of Arrays, which does not implement methods to modify itself. Arrays.asList is only a transferred interface, data inside which is stored as an array.\n\n    ```java\n    String[] str = new String[] { \"a\", \"b\" };\n    List<String> list = Arrays.asList(str); \n    ```\nCase 1: list.add(\"c\"); will throw a runtime exception.  \nCase 2: str[0]= \"gujin\"; list.get(0) will be modified.\n* 5 ``[Mandatory]`` Do not remove or add elements to a collection in a foreach loop. Please use Iterator to remove an item. Iterator object should be synchronized when executing concurrent operations.  \nCounter example:\n\n    ```java\n    List<String> a = new ArrayList<String>();\n    a.add(\"1\");\n    a.add(\"2\");\n    for (String temp : a) {\n        if (\"1\".equals(temp)) {\n            a.remove(temp);\n        }\n    }\n    ```\n    Note: If you try to replace \"1\" with \"2\", you will get an unexpected result.\nPositive example:\n\n    ```java\n    Iterator<String> it = a.iterator();\n    while (it.hasNext()) {    \n            String temp =  it.next();             \n            if (delete condition) {              \n                  it.remove();       \n            }\n        }    \n    ```\n* 6``[Recommended]`` Set a size when initializing a collection if possible.  \nNote: Better to use ArrayList(int initialCapacity) to initialize ArrayList.\n\n\n### <font color=\"green\">Naming Conventions</font>\n* 1 ``[Mandatory]`` No identifier name should start or end with an underline or a dollar sign.  \nCounter example: _name / __name / $Object / name_ / name$ / Object$\n\n* 2 ``[Mandatory]`` Using Chinese, Pinyin, or Pinyin-English mixed spelling in naming is strictly prohibited. Accurate English spelling and grammar will make the code readable, understandable, and maintainable.\nPositive example: alibaba / taobao / youku / Hangzhou. In these cases, Chinese proper names in Pinyin are acceptable.\n\n* 3 ``[Mandatory]`` Class names should be nouns in UpperCamelCase except domain models: DO, BO, DTO, VO, etc.\nPositive example: MarcoPolo / UserDO / HtmlDTO / XmlService / TcpUdpDeal / TaPromotion\nCounter example: macroPolo / UserDo / HTMLDto / XMLService / TCPUDPDeal / TAPromotion\n\n* 4 ``[Mandatory]`` Method names, parameter names, member variable names, and local variable names should be written in lowerCamelCase.\nPositive example: localValue / getHttpMessage() / inputUserId\n\n* 5 ``[Mandatory]`` Constant variable names should be written in upper characters separated by underscores. These names should be semantically complete and clear.\nPositive example: MAX_STOCK_COUNT\nCounter example: MAX_COUNT\n\n* 6 ``[Mandatory]`` Abstract class names must start with Abstract or Base. Exception class names must end with Exception. Test cases shall start with the class names to be tested and end with Test.\n\n* 7 ``[Mandatory]`` Brackets are a part of an Array type. The definition could be: String[] args;\nCounter example: String args[];\n\n* 8 ``[Mandatory]`` Do not add 'is' as prefix while defining Boolean variable, since it may cause a serialization exception in some Java Frameworks.\nCounter example: boolean isSuccess; The method name will be isSuccess() and then RPC framework will deduce the variable name as 'success', resulting in a serialization error since it cannot find the correct attribute.\n\n* 9 ``[Mandatory]`` Package should be named in lowercase characters. There should be only one English word after each dot. Package names are always in singular format while class name can be in plural format if necessary.  \nPositive example: com.alibaba.open.util can be used as package name for utils;\n* 10 There are mainly two rules for interface and corresponding implementation class naming:\n    1. ``[Mandatory]`` All Service and DAO classes must be interface based on SOA principle. Implementation class names should be ended with Impl.  \nPositive example: CacheServiceImpl to implement CacheService.\n    2. ``[Recommended]`` If the interface name is to indicate the ability of the interface, then its name should be adjective.  \nPositive example: AbstractTranslator to implement Translatable.\n\n### <font color=\"green\">Constant Conventions</font>\n\n* 1 ``[Mandatory]`` Magic values, except for predefined, are forbidden in coding.\nCounter example: String key=\"Id#taobao_\" + tradeId;\n* 2 ``[Mandatory]`` 'L' instead of 'l' should be used for long or Long variable because 'l' is easily to be regarded as number 1 in mistake.  \nCounter example: Long a=2l, it is hard to tell whether it is number 21 or Long 2.\n\n### <font color=\"green\">OOP</font>\n* 1 ``[Mandatory]`` Using a deprecated class or method is prohibited.  \nNote: For example, decode(String source, String encode) should be used instead of the deprecated method decode(String encodeStr). Once an interface has been deprecated, the interface provider has the obligation to provide a new one. At the same time, client programmers have the obligation to check out what its new implementation is.\n* 2 ``[Mandatory]`` Since NullPointerException can possibly be thrown while calling the equals method of Object, equals should be invoked by a constant or an object that is definitely not null.  \nPositive example: \"test\".equals(object);  \nCounter example: object.equals(\"test\");  \nNote: java.util.Objects#equals (a utility class in JDK7) is recommended.\n\n* 3 ``[Mandatory]`` The wrapper classes should be compared by equals method rather than by symbol of '==' directly.  \nNote: Consider this assignment: Integer var = ?. When it fits the range from -128 to 127, we can use == directly for a comparison. Because the Integer object will be generated by IntegerCache.cache, which reuses an existing object. Nevertheless, when it fits the complementary set of the former range, the Integer object will be allocated in Heap, which does not reuse an existing object. This is an [implementation-level detail](https://docs.oracle.com/javase/specs/jls/se9/html/jls-5.html#jls-5.1.7-300) that should NOT be relied upon. Hence using the equals method is always recommended.\n* 4 ``[Mandatory]`` Rules for using primitive data types and wrapper classes:\n    1. Members of a POJO class must be wrapper classes.\n    2. The return value and arguments of a RPC method must be wrapper classes.\n    3. ``[Recommended]`` Local variables should be primitive data types.    \nNote: In order to remind the consumer of explicit assignments, there are no initial values for members in a POJO class. As a consumer, you should check problems such as NullPointerException and warehouse entries for yourself.\n Positive example: As the result of a database query may be null, assigning it to a primitive date type will cause a risk of NullPointerException because of Unboxing.  \n Counter example: Consider the output of a transaction volume's amplitude, like ±x%. As a primitive data, when it comes to a failure of calling a RPC service, the default return value: 0% will be assigned, which is not correct. A hyphen like - should be assigned instead. Therefore, the null value of a wrapper class can represent additional information, such as a failure of calling a RPC service, an abnormal exit, etc.\n* 5 ``[Mandatory]`` While defining POJO classes like DO, DTO, VO, etc., do not assign any default values to the members.  \n* 6 ``[Mandatory]`` The toString method must be implemented in a POJO class. The super.toString method should be called in front of the whole implementation if the current class extends another POJO class.  \nNote: We can call the toString method in a POJO directly to print property values in order to check the problem when a method throws an exception in runtime.\n* 7 ``[Recommended]`` Use the append method in StringBuilder inside a loop body when concatenating multiple strings.  \n\n    Counter example:\n\n    ```java\n    String str = \"start\";  \n    for(int i=0; i<100; i++) {  \n        str = str + \"hello\";  \n    }\n    ```\n    \n    Note: According to the decompiled bytecode file, for each iteration, it allocates a new StringBuilder object, appends a string, and finally returns a String object via the toString method. This is a tremendous waste of memory, especially when the iteration count is large.\n\n### <font color=\"green\">Flow Control Statements</font>\n* 1 ``[Mandatory]`` In a switch block, each case should be finished by break/return. If not, a note should be included to describe at which case it will stop. Within every switch block, a default statement must be present, even if it is empty.\n* 2 ``[Mandatory]`` Braces are used with if, else, for, do and while statements, even if the body contains only a single statement. Avoid using the following example:\n\n    ```java\n    if (condition) statements; \n    ```\n* 3 ``[Recommended]`` Do not use complicated expressions in conditional statements (except for frequently used methods like getXxx/isXxx). Using boolean variables to store results of complicated expressions temporarily will increase the code's readability.\nNote: Logic within many if statements are very complicated. Readers need to analyze the final results of the conditional expression to understand the branching logic.  \nPositive example:\n\n    ```java\n    // please refer to the pseudo-code as follows \n    boolean existed = (file.open(fileName, \"w\") != null) && (...) || (...);\n    if (existed) {\n        //...\n    }  \n    ```\n\n    Counter example:  \n\n    ```java\n    if ((file.open(fileName, \"w\") != null) && (...) || (...)) {\n       // ...\n    }\n    ```\n* 4 ``[Recommended]`` Avoid using the negation operator '!'.\nNote: The negation operator is not easy to be quickly understood. There must be a positive way to represent the same logic.\n\n### <font color=\"green\">Exception</font>\n* 1 ``[Mandatory]`` Make sure to invoke the rollback if a method throws an Exception. Rollbacks are based on the context of the coding logic.\n* 2 ``[Mandatory]`` Never use return within a finally block. A return statement in a finally block will cause exceptions or result in a discarded return value in the try-catch block.\n* 3 ``[Recommended]`` One of the most common errors is NullPointerException. Pay attention to the following situations:\n    * 1 If the return type is primitive, return a value of wrapper class may cause NullPointerException.\n      Counter example: public int f() { return Integer } Unboxing a null value will throw a NullPointerException.\n    * 2 The return value of a database query might be null.\n    * 3 Elements in collection may be null, even though Collection.isEmpty() returns false.\n    * 4 Return values from an RPC might be null.\n    * 5 Data stored in sessions might by null.\n    * 6 Method chaining, like obj.getA().getB().getC(), is likely to cause NullPointerException.  \n      Positive example: Use Optional to avoid null check and NPE (Java 8+).\n\n### <font color=\"green\">Code Comments</font>\n* 1 ``[Mandatory]`` Javadoc should be used for classes, class variables and methods. The format should be '/** comment **/', rather than '// xxx'.  \nNote: In IDE, Javadoc can be seen directly when hovering, which is a good way to improve efficiency.\n* 2 ``[Mandatory]`` Abstract methods (including methods in interface) should be commented by Javadoc. Javadoc should include method instruction, description of parameters, return values and possible exceptions.\n* 3 ``[Mandatory]`` Every class should include information of author(s) and date.\n* 4 ``[Mandatory]`` Single line comments in a method should be put above the code to be commented, by using // and multiple lines by using /* */. Alignment for comments should be noticed carefully.\n* 5 ``[Mandatory]`` All enumeration type fields should be commented as Javadoc style.\n* 6 ``[Recommended]`` Codes or configuration that is noticed to be obsoleted should be resolutely removed from projects.\n\n\n### <font color=\"green\">Other</font>\n* 1``[Mandatory]`` Avoid using *Apache Beanutils* to copy attributes.\n* 2 ``[Mandatory]`` When using regex, precompile needs to be done in order to increase the matching performance and preferably stored as a constant.  \nNote: Do not define Pattern pattern = Pattern.compile(.); within method body.\n* 3 ``[Mandatory]`` Variables must add exclamatory mark when passing to velocity engine from backend, like $!{var}.  \nNote: If attribute is null or does not exist, ${var} will be shown directly on web pages.\n* 4 ``[Mandatory]`` The return type of Math.random() is double, value range is 0<=x<1 (0 is possible). If a random integer is required, do not multiply x by 10 then round the result. The correct way is to use nextInt or nextLong method which belong to Random Object.\n* 5 ``[Mandatory]`` Use System.currentTimeMillis() to get the current millisecond. Do not use new Date().getTime().   \nNote: In order to get a more accurate time, use System.nanoTime(). In JDK8, use Instant class to deal with situations like time statistics.\n* 6 ``[Mandatory]`` When doing date formatting, \"y\" should be written in lowercase for \"year\" in a pattern statement.\nNote: When doing date formatting, \"yyyy\" represents the day in which year, while \"YYYY\" represents the week in which year (a concept introduced in JDK7). If a week is across two years, the returning \"YYYY\"represents the next year.\n    \n    Some more points need to be notices:\n     * Uppercase \"M\" stands for month.\n     * Lowercase \"m\" stands for minute.\n     * Uppercase \"H\" stands for 24-hour clock.\n     * Lowercase \"h\" stands for 12-hour clock.\n\n    Positive Example: Example pattern for date formatting:\n\n    ```java\n    new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n    ```\n    \n    Counter Example: Someone applied \"YYYY/MM/dd\" pattern for date formatting, and the execution result of 2017/12/31 was 2018/12/31, leading to a serious failure.\n* 7 ``[Recommended]`` The total number of lines for a method should not be more than 80.\nNote: The total number of lines, including the method signature, closing brace, codes, comments, blank lines, line breaks and any invisible lines, should not be more than 80.\n"
  },
  {
    "path": "p3c-pmd/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<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\">\n  <modelVersion>4.0.0</modelVersion>\n  <parent>\n    <groupId>org.sonatype.oss</groupId>\n    <artifactId>oss-parent</artifactId>\n    <version>9</version>\n  </parent>\n  <groupId>com.alibaba.p3c</groupId>\n  <artifactId>p3c-pmd</artifactId>\n  <version>2.1.1</version>\n  <packaging>jar</packaging>\n  <name>p3c-pmd</name>\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <pmd.version>6.15.0</pmd.version>\n    <maven.compiler.target>1.8</maven.compiler.target>\n    <annotation.version>1.3.2</annotation.version>\n    <kotlin.version>1.3.72</kotlin.version>\n  </properties>\n  <description>Alibaba Java Coding Guidelines PMD implementations</description>\n  <url>https://github.com/alibaba/p3c</url>\n  <inceptionYear>2017</inceptionYear>\n\n  <licenses>\n    <license>\n      <name>Apache 2</name>\n      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n      <distribution>repo</distribution>\n      <comments>A business-friendly OSS license</comments>\n    </license>\n  </licenses>\n\n  <scm>\n    <url>https://github.com/alibaba/p3c</url>\n    <connection>scm:git:https://git@github.com/alibaba/p3c.git</connection>\n  </scm>\n\n  <organization>\n    <name>Alibaba Group</name>\n    <url>https://github.com/alibaba</url>\n  </organization>\n\n  <developers>\n    <developer>\n      <name>XuanTan</name>\n      <url>https://github.com/xuantan</url>\n      <email>zhangym124@gmail.com</email>\n    </developer>\n    <developer>\n      <name>ChangLe</name>\n      <url>https://github.com/LQZYC</url>\n      <email>lqleo323@gmail.com</email>\n    </developer>\n    <developer>\n      <name>ZengHou</name>\n      <url>https://github.com/fw8899</url>\n      <email>fengwei1983@gmail.com</email>\n    </developer>\n    <developer>\n      <name>ShengYan</name>\n      <url>http://smiler158.github.io/</url>\n      <email>smiler158@163.com</email>\n    </developer>\n    <developer>\n      <name>KeQi</name>\n      <email>lyzw2009@gmail.com</email>\n    </developer>\n    <developer>\n      <name>JunLie</name>\n      <url>https://github.com/SeanCai</url>\n      <email>sean.caikang@gmail.com</email>\n    </developer>\n    <developer>\n      <name>MoYan</name>\n      <url>https://github.com/imu2008</url>\n      <email>panhuawenmail@gmail.com</email>\n    </developer>\n  </developers>\n  <dependencies>\n    <dependency>\n      <groupId>net.sourceforge.pmd</groupId>\n      <artifactId>pmd-java</artifactId>\n      <version>${pmd.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>net.sourceforge.pmd</groupId>\n      <artifactId>pmd-vm</artifactId>\n      <version>${pmd.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>net.sourceforge.pmd</groupId>\n      <artifactId>pmd-test</artifactId>\n      <version>${pmd.version}</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>javax.annotation</groupId>\n      <artifactId>javax.annotation-api</artifactId>\n      <version>${annotation.version}</version>\n    </dependency>\n    <dependency>\n      <groupId>org.jetbrains.kotlin</groupId>\n      <artifactId>kotlin-stdlib-jdk8</artifactId>\n      <version>${kotlin.version}</version>\n    </dependency>\n  </dependencies>\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-pmd-plugin</artifactId>\n        <version>3.11.0</version>\n        <configuration>\n          <sourceEncoding>${project.build.sourceEncoding}</sourceEncoding>\n          <targetJdk>${maven.compiler.target}</targetJdk>\n          <printFailingErrors>true</printFailingErrors>\n          <rulesets>\n            <ruleset>rulesets/java/ali-comment.xml</ruleset>\n            <ruleset>rulesets/java/ali-concurrent.xml</ruleset>\n            <ruleset>rulesets/java/ali-constant.xml</ruleset>\n            <ruleset>rulesets/java/ali-exception.xml</ruleset>\n            <ruleset>rulesets/java/ali-flowcontrol.xml</ruleset>\n            <ruleset>rulesets/java/ali-naming.xml</ruleset>\n            <ruleset>rulesets/java/ali-oop.xml</ruleset>\n            <ruleset>rulesets/java/ali-orm.xml</ruleset>\n            <ruleset>rulesets/java/ali-other.xml</ruleset>\n            <ruleset>rulesets/java/ali-set.xml</ruleset>\n          </rulesets>\n          <excludes>\n            <exclude>**/FixClassTypeResolver.java</exclude>\n          </excludes>\n        </configuration>\n        <executions>\n          <execution>\n            <phase>verify</phase>\n            <goals>\n              <goal>check</goal>\n            </goals>\n          </execution>\n        </executions>\n        <dependencies>\n          <dependency>\n            <groupId>com.alibaba.p3c</groupId>\n            <artifactId>p3c-pmd</artifactId>\n            <version>2.0.1</version>\n          </dependency>\n        </dependencies>\n      </plugin>\n      <plugin>\n        <artifactId>kotlin-maven-plugin</artifactId>\n        <groupId>org.jetbrains.kotlin</groupId>\n        <version>${kotlin.version}</version>\n        <executions>\n          <execution>\n            <id>compile</id>\n            <goals>\n              <goal>compile</goal>\n            </goals>\n            <configuration>\n              <sourceDirs>\n                <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>\n                <sourceDir>${project.basedir}/src/main/java</sourceDir>\n              </sourceDirs>\n            </configuration>\n          </execution>\n          <execution>\n            <id>test-compile</id>\n            <goals>\n              <goal>test-compile</goal>\n            </goals>\n            <configuration>\n              <sourceDirs>\n                <sourceDir>${project.basedir}/src/test/kotlin</sourceDir>\n                <sourceDir>${project.basedir}/src/test/java</sourceDir>\n              </sourceDirs>\n            </configuration>\n          </execution>\n        </executions>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <version>3.8.0</version>\n        <configuration>\n          <source>${maven.compiler.target}</source>\n          <target>${maven.compiler.target}</target>\n          <encoding>UTF-8</encoding>\n        </configuration>\n        <executions>\n          <!-- Replacing default-compile as it is treated specially by maven -->\n          <execution>\n            <id>default-compile</id>\n            <phase>none</phase>\n          </execution>\n          <!-- Replacing default-testCompile as it is treated specially by maven -->\n          <execution>\n            <id>default-testCompile</id>\n            <phase>none</phase>\n          </execution>\n          <execution>\n            <id>java-compile</id>\n            <phase>compile</phase>\n            <goals>\n              <goal>compile</goal>\n            </goals>\n          </execution>\n          <execution>\n            <id>java-test-compile</id>\n            <phase>test-compile</phase>\n            <goals>\n              <goal>testCompile</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n      <plugin>\n        <artifactId>maven-assembly-plugin</artifactId>\n        <version>3.0.0</version>\n        <configuration>\n          <descriptorRefs>\n            <descriptorRef>jar-with-dependencies</descriptorRef>\n          </descriptorRefs>\n        </configuration>\n        <executions>\n          <execution>\n            <id>make-assembly</id>\n            <phase>package</phase>\n            <goals>\n              <goal>single</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-javadoc-plugin</artifactId>\n        <version>2.10.4</version>\n        <executions>\n          <execution>\n            <id>attach-javadocs</id>\n            <goals>\n              <goal>jar</goal>\n            </goals>\n          </execution>\n        </executions>\n        <configuration>\n          <tags>\n            <tag>\n              <name>date</name>\n            </tag>\n          </tags>\n        </configuration>\n      </plugin>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-gpg-plugin</artifactId>\n        <version>1.6</version>\n        <executions>\n          <execution>\n            <id>sign-artifacts</id>\n            <phase>verify</phase>\n            <goals>\n              <goal>sign</goal>\n            </goals>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/I18nResources.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd;\n\nimport java.io.BufferedInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.MissingResourceException;\nimport java.util.Properties;\nimport java.util.ResourceBundle;\nimport java.util.ResourceBundle.Control;\n\n/**\n * @author caikang\n * @date 2017/05/24\n */\npublic class I18nResources {\n    private static final String XML_LITERAL = \"xml\";\n\n    private static String lang = System.getProperty(\"pmd.language\", \"zh\");\n\n    private static Locale currentLocale;\n\n    private static ResourceBundle resourceBundle = changeLanguage(lang);\n\n    public static ResourceBundle changeLanguage(String language) {\n        Locale locale = Locale.CHINESE.getLanguage().equals(language) ? Locale.CHINESE : Locale.ENGLISH;\n        return changeLanguage(locale);\n    }\n\n    public static ResourceBundle changeLanguage(Locale locale) {\n        if (currentLocale != null && currentLocale.equals(locale)) {\n            return resourceBundle;\n        }\n        currentLocale = locale;\n        resourceBundle = ResourceBundle.getBundle(\"messages\", locale, new XmlControl());\n        return resourceBundle;\n    }\n\n    public static String getMessage(String key) {\n        if (key == null) {\n            // 暂时返回空字符串\n            return \"\";\n        }\n        try {\n            return resourceBundle.getString(key).trim();\n        } catch (MissingResourceException e) {\n            return key;\n        }\n    }\n\n    public static String getMessage(String key, Object... params) {\n        String value = getMessage(key);\n        if (params == null || params.length == 0) {\n            return value;\n        }\n        return String.format(value, params);\n    }\n\n    public static String getMessageWithExceptionHandled(String key) {\n        if (key == null) {\n            // 暂时返回空字符串\n            return \"\";\n        }\n        try {\n            return resourceBundle.getString(key).trim();\n        } catch (MissingResourceException e) {\n            return key;\n        }\n    }\n\n    public static class XmlResourceBundle extends ResourceBundle {\n        private Properties props;\n\n        XmlResourceBundle(InputStream stream) throws IOException {\n            props = new Properties();\n            props.loadFromXML(stream);\n        }\n\n        @Override\n        protected Object handleGetObject(String key) {\n            return props.getProperty(key);\n        }\n\n        @Override\n        public Enumeration<String> getKeys() {\n            List<String> keys = new ArrayList<>();\n            Enumeration<Object> enumeration = props.keys();\n            while (enumeration.hasMoreElements()) {\n                keys.add((String)enumeration.nextElement());\n            }\n            return Collections.enumeration(keys);\n        }\n    }\n\n    public static class XmlControl extends Control {\n        @Override\n        public List<String> getFormats(String baseName) {\n            if (baseName == null) {\n                throw new NullPointerException();\n            }\n            return Collections.singletonList(XML_LITERAL);\n        }\n\n        @Override\n        public Locale getFallbackLocale(String baseName, Locale locale) {\n            return null;\n        }\n\n        @Override\n        public ResourceBundle newBundle(String baseName,\n            Locale locale,\n            String format,\n            ClassLoader loader,\n            boolean reload)\n            throws IllegalAccessException,\n            InstantiationException,\n            IOException {\n            if (baseName == null || locale == null\n                || format == null || loader == null) {\n                throw new NullPointerException();\n            }\n            ResourceBundle bundle = null;\n            if (XML_LITERAL.equals(format)) {\n                String bundleName = toBundleName(baseName, locale);\n                String resourceName = toResourceName(bundleName, format);\n                InputStream stream;\n                if (reload) {\n                    stream = getInputStream(loader, resourceName);\n                } else {\n                    stream = loader.getResourceAsStream(resourceName);\n                }\n                if (stream != null) {\n                    BufferedInputStream bis = new BufferedInputStream(stream);\n                    bundle = new XmlResourceBundle(bis);\n                    bis.close();\n                }\n            }\n            return bundle;\n        }\n\n        private InputStream getInputStream(ClassLoader loader, String resourceName)\n            throws IOException {\n            URL url = loader.getResource(resourceName);\n            if (url == null) {\n                return null;\n            }\n            URLConnection connection = url.openConnection();\n            if (connection == null) {\n                return null;\n            }\n            // Disable caches to get fresh data for\n            // reloading.\n            connection.setUseCaches(false);\n            return connection.getInputStream();\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/fix/FixClassTypeResolver.java",
    "content": "/**\n * BSD-style license; for more info see http://pmd.sourceforge.net/license.html\n */\npackage com.alibaba.p3c.pmd.fix;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport javax.annotation.Generated;\n\nimport com.alibaba.p3c.pmd.lang.java.util.NumberConstants;\nimport com.alibaba.p3c.pmd.lang.java.util.StringAndCharConstants;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTAdditiveExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTAndExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits;\nimport net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;\nimport net.sourceforge.pmd.lang.java.ast.ASTCastExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTConditionalAndExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTConditionalOrExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTExclusiveOrExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTInclusiveOrExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTInstanceOfExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTLiteral;\nimport net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;\nimport net.sourceforge.pmd.lang.java.ast.ASTMultiplicativeExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTNormalAnnotation;\nimport net.sourceforge.pmd.lang.java.ast.ASTNullLiteral;\nimport net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTPostfixExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPreDecrementExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPreIncrementExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;\nimport net.sourceforge.pmd.lang.java.ast.ASTReferenceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTShiftExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTSingleMemberAnnotation;\nimport net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTType;\nimport net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\nimport net.sourceforge.pmd.lang.java.ast.TypeNode;\nimport net.sourceforge.pmd.lang.java.typeresolution.ClassTypeResolver;\nimport net.sourceforge.pmd.lang.java.typeresolution.PMDASMClassLoader;\n\n//\n// Helpful reading:\n// http://www.janeg.ca/scjp/oper/promotions.html\n// http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html\n//\n\n/**\n * 1. custom type resolver，fix bug: resolve type of anonymous class failed 2. set anonymous class to parent's type\n *\n * @author unknown\n * @date 2016/11/21\n */\n@Generated(\"from pmd\")\npublic class FixClassTypeResolver extends ClassTypeResolver {\n\n    private static final Logger LOG = Logger.getLogger(FixClassTypeResolver.class.getName());\n\n    private static final Map<String, Class<?>> PRIMITIVE_TYPES;\n    private static final Map<String, String> JAVA_LANG;\n    private static final String DOT_STRING = \".\";\n    private static final String EXCLAMATION = \"!\";\n\n    static {\n        // Note: Assumption here that primitives come from same parent\n        // ClassLoader regardless of what ClassLoader we are passed\n        Map<String, Class<?>> thePrimitiveTypes = new HashMap<>();\n        thePrimitiveTypes.put(\"void\", Void.TYPE);\n        thePrimitiveTypes.put(boolean.class.getName(), Boolean.TYPE);\n        thePrimitiveTypes.put(byte.class.getName(), Byte.TYPE);\n        thePrimitiveTypes.put(char.class.getName(), Character.TYPE);\n        thePrimitiveTypes.put(short.class.getName(), Short.TYPE);\n        thePrimitiveTypes.put(int.class.getName(), Integer.TYPE);\n        thePrimitiveTypes.put(long.class.getName(), Long.TYPE);\n        thePrimitiveTypes.put(float.class.getName(), Float.TYPE);\n        thePrimitiveTypes.put(double.class.getName(), Double.TYPE);\n        PRIMITIVE_TYPES = Collections.unmodifiableMap(thePrimitiveTypes);\n\n        Map<String, String> theJavaLang = new HashMap<>();\n        theJavaLang.put(\"Boolean\", \"java.lang.Boolean\");\n        theJavaLang.put(\"Byte\", \"java.lang.Byte\");\n        theJavaLang.put(\"Character\", \"java.lang.Character\");\n        theJavaLang.put(\"CharSequence\", \"java.lang.CharSequence\");\n        theJavaLang.put(\"Class\", \"java.lang.Class\");\n        theJavaLang.put(\"ClassLoader\", \"java.lang.ClassLoader\");\n        theJavaLang.put(\"Cloneable\", \"java.lang.Cloneable\");\n        theJavaLang.put(\"Comparable\", \"java.lang.Comparable\");\n        theJavaLang.put(\"Compiler\", \"java.lang.Compiler\");\n        theJavaLang.put(\"Double\", \"java.lang.Double\");\n        theJavaLang.put(\"Float\", \"java.lang.Float\");\n        theJavaLang.put(\"InheritableThreadLocal\", \"java.lang.InheritableThreadLocal\");\n        theJavaLang.put(\"Integer\", \"java.lang.Integer\");\n        theJavaLang.put(\"Long\", \"java.lang.Long\");\n        theJavaLang.put(\"Math\", \"java.lang.Math\");\n        theJavaLang.put(\"Number\", \"java.lang.Number\");\n        theJavaLang.put(\"Object\", \"java.lang.Object\");\n        theJavaLang.put(\"Package\", \"java.lang.Package\");\n        theJavaLang.put(\"Process\", \"java.lang.Process\");\n        theJavaLang.put(\"Runnable\", \"java.lang.Runnable\");\n        theJavaLang.put(\"Runtime\", \"java.lang.Runtime\");\n        theJavaLang.put(\"RuntimePermission\", \"java.lang.RuntimePermission\");\n        theJavaLang.put(\"SecurityManager\", \"java.lang.SecurityManager\");\n        theJavaLang.put(\"Short\", \"java.lang.Short\");\n        theJavaLang.put(\"StackTraceElement\", \"java.lang.StackTraceElement\");\n        theJavaLang.put(\"StrictMath\", \"java.lang.StrictMath\");\n        theJavaLang.put(\"String\", \"java.lang.String\");\n        theJavaLang.put(\"StringBuffer\", \"java.lang.StringBuffer\");\n        theJavaLang.put(\"System\", \"java.lang.System\");\n        theJavaLang.put(\"Thread\", \"java.lang.Thread\");\n        theJavaLang.put(\"ThreadGroup\", \"java.lang.ThreadGroup\");\n        theJavaLang.put(\"ThreadLocal\", \"java.lang.ThreadLocal\");\n        theJavaLang.put(\"Throwable\", \"java.lang.Throwable\");\n        theJavaLang.put(\"Void\", \"java.lang.Void\");\n        JAVA_LANG = Collections.unmodifiableMap(theJavaLang);\n    }\n\n    private final PMDASMClassLoader pmdClassLoader;\n    private Map<String, String> importedClasses;\n    private List<String> importedOnDemand;\n    private int anonymousClassCounter = 0;\n\n    public FixClassTypeResolver() {\n        this(FixClassTypeResolver.class.getClassLoader());\n    }\n\n    public FixClassTypeResolver(ClassLoader classLoader) {\n        pmdClassLoader = PMDASMClassLoader.getInstance(classLoader);\n    }\n\n    // FUTURE ASTCompilationUnit should not be a TypeNode. Clean this up\n    // accordingly.\n    @Override\n    public Object visit(ASTCompilationUnit node, Object data) {\n        String className = null;\n        try {\n            importedOnDemand = new ArrayList<>();\n            importedClasses = new HashMap<>(16);\n            className = getClassName(node);\n            if (className != null) {\n                populateClassName(node, className);\n            }\n        } catch (ClassNotFoundException | NoClassDefFoundError e) {\n            if (LOG.isLoggable(Level.FINE)) {\n                LOG.log(Level.FINE, \"Could not find class \" + className + \", due to: \" + e);\n            }\n        } catch (LinkageError e) {\n            if (LOG.isLoggable(Level.WARNING)) {\n                LOG.log(Level.WARNING, \"Could not find class \" + className + \", due to: \" + e);\n            }\n        } finally {\n            populateImports(node);\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTImportDeclaration node, Object data) {\n        ASTName importedType = (ASTName)node.jjtGetChild(0);\n        if (importedType.getType() != null) {\n            node.setType(importedType.getType());\n        } else {\n            populateType(node, importedType.getImage());\n        }\n\n        if (node.getType() != null) {\n            node.setPackage(node.getType().getPackage());\n        }\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTTypeDeclaration node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTClassOrInterfaceType node, Object data) {\n        String typeName = node.getImage();\n        populateType(node, typeName);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        populateType(node, node.getImage());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTEnumDeclaration node, Object data) {\n        populateType(node, node.getImage());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTAnnotationTypeDeclaration node, Object data) {\n        populateType(node, node.getImage());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTName node, Object data) {\n        /*\n         * Only doing this for nodes where getNameDeclaration is null this means\n         * it's not a named node, i.e. Static reference or Annotation Doing this\n         * for memory - TODO: Investigate if there is a valid memory concern or\n         * not\n         */\n        if (node.getNameDeclaration() == null) {\n            // Skip these scenarios as there is no type to populate in these\n            // cases:\n            // 1) Parent is a PackageDeclaration, which is not a type\n            // 2) Parent is a ImportDeclaration, this is handled elsewhere.\n            if (!(node.jjtGetParent() instanceof ASTPackageDeclaration\n                || node.jjtGetParent() instanceof ASTImportDeclaration)) {\n                String name = node.getImage();\n                if (name.indexOf(StringAndCharConstants.DOT) != -1) {\n                    name = name.substring(0, name.indexOf(StringAndCharConstants.DOT));\n                }\n                populateType(node, name);\n            }\n        } else {\n            // Carry over the type from the declaration\n            if (node.getNameDeclaration().getNode() instanceof TypeNode) {\n                node.setType(((TypeNode)node.getNameDeclaration().getNode()).getType());\n            }\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTFieldDeclaration node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTVariableDeclarator node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTVariableDeclaratorId node, Object data) {\n        if (node == null || node.getNameDeclaration() == null) {\n            return super.visit(node, data);\n        }\n        String name = node.getNameDeclaration().getTypeImage();\n        if (name != null) {\n            populateType(node, name);\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTType node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTReferenceType node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTPrimitiveType node, Object data) {\n        populateType(node, node.getImage());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTConditionalExpression node, Object data) {\n        super.visit(node, data);\n        // noinspection StatementWithEmptyBody\n        if (node.isTernary()) {\n            // TODO Rules for Ternary are complex\n        } else {\n            rollupTypeUnary(node);\n        }\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTConditionalOrExpression node, Object data) {\n        populateType(node, boolean.class.getName());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTConditionalAndExpression node, Object data) {\n        populateType(node, boolean.class.getName());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTInclusiveOrExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeBinaryNumericPromotion(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTExclusiveOrExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeBinaryNumericPromotion(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTAndExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeBinaryNumericPromotion(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTEqualityExpression node, Object data) {\n        populateType(node, boolean.class.getName());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTInstanceOfExpression node, Object data) {\n        populateType(node, boolean.class.getName());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTRelationalExpression node, Object data) {\n        populateType(node, boolean.class.getName());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTShiftExpression node, Object data) {\n        super.visit(node, data);\n        // Unary promotion on LHS is type of a shift operation\n        rollupTypeUnaryNumericPromotion(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTAdditiveExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeBinaryNumericPromotion(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTMultiplicativeExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeBinaryNumericPromotion(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTUnaryExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnaryNumericPromotion(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTPreIncrementExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTPreDecrementExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) {\n        super.visit(node, data);\n        if (EXCLAMATION.equals(node.getImage())) {\n            populateType(node, boolean.class.getName());\n        } else {\n            rollupTypeUnary(node);\n        }\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTPostfixExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTCastExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTPrimaryExpression node, Object data) {\n        super.visit(node, data);\n        if (node.jjtGetNumChildren() == 1) {\n            rollupTypeUnary(node);\n        } else {\n            // TODO OMG, this is complicated. PrimaryExpression, PrimaryPrefix\n            // and PrimarySuffix are all related.\n        }\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTPrimaryPrefix node, Object data) {\n        super.visit(node, data);\n        if (node.getImage() == null) {\n            rollupTypeUnary(node);\n        } else {\n            // TODO OMG, this is complicated. PrimaryExpression, PrimaryPrefix\n            // and PrimarySuffix are all related.\n        }\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTPrimarySuffix node, Object data) {\n        super.visit(node, data);\n        // TODO OMG, this is complicated. PrimaryExpression, PrimaryPrefix and\n        // PrimarySuffix are all related.\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTNullLiteral node, Object data) {\n        // No explicit type\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTBooleanLiteral node, Object data) {\n        populateType(node, boolean.class.getName());\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTLiteral node, Object data) {\n        super.visit(node, data);\n        if (node.jjtGetNumChildren() != 0) {\n            rollupTypeUnary(node);\n        } else {\n            if (node.isIntLiteral()) {\n                populateType(node, int.class.getName());\n            } else if (node.isLongLiteral()) {\n                populateType(node, long.class.getName());\n            } else if (node.isFloatLiteral()) {\n                populateType(node, float.class.getName());\n            } else if (node.isDoubleLiteral()) {\n                populateType(node, double.class.getName());\n            } else if (node.isCharLiteral()) {\n                populateType(node, char.class.getName());\n            } else if (node.isStringLiteral()) {\n                populateType(node, String.class.getName());\n            } else {\n                throw new IllegalStateException(\"PMD error, unknown literal type!\");\n            }\n        }\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTAllocationExpression node, Object data) {\n        super.visit(node, data);\n        boolean notRollupTypeUnary = node.jjtGetNumChildren() >= NumberConstants.INTEGER_SIZE_OR_LENGTH_2\n            && node.jjtGetChild(1) instanceof ASTArrayDimsAndInits\n            || node.jjtGetNumChildren() >= NumberConstants.INTEGER_SIZE_OR_LENGTH_3\n            && node.jjtGetChild(NumberConstants.INDEX_2) instanceof ASTArrayDimsAndInits;\n        if (!notRollupTypeUnary) {\n            rollupTypeUnary(node);\n        }\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTStatementExpression node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTNormalAnnotation node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTMarkerAnnotation node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTSingleMemberAnnotation node, Object data) {\n        super.visit(node, data);\n        rollupTypeUnary(node);\n        return data;\n    }\n\n    /**\n     * Roll up the type based on type of the first child node.\n     *\n     * @param typeNode type node\n     */\n    private void rollupTypeUnary(TypeNode typeNode) {\n        Node node = typeNode;\n        if (node.jjtGetNumChildren() >= 1) {\n            Node child = node.jjtGetChild(0);\n            if (child instanceof TypeNode) {\n                typeNode.setType(((TypeNode)child).getType());\n            }\n        }\n    }\n\n    /**\n     * Roll up the type based on type of the first child node using Unary\n     * Numeric Promotion per JLS 5.6.1\n     *\n     * @param typeNode type node\n     */\n    private void rollupTypeUnaryNumericPromotion(TypeNode typeNode) {\n        Node node = typeNode;\n        if (node.jjtGetNumChildren() >= 1) {\n            Node child = node.jjtGetChild(0);\n            if (child instanceof TypeNode) {\n                Class<?> type = ((TypeNode)child).getType();\n                if (type != null) {\n                    if (byte.class.getName().equals(type.getName()) || short.class.getName().equals(type.getName())\n                        || char.class.getName().equals(type.getName())) {\n                        populateType(typeNode, int.class.getName());\n                    } else {\n                        typeNode.setType(((TypeNode)child).getType());\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Roll up the type based on type of the first and second child nodes using\n     * Binary Numeric Promotion per JLS 5.6.2\n     *\n     * @param typeNode type node\n     */\n    private void rollupTypeBinaryNumericPromotion(TypeNode typeNode) {\n        Node node = typeNode;\n        if (node.jjtGetNumChildren() >= NumberConstants.INTEGER_SIZE_OR_LENGTH_2) {\n            Node child1 = node.jjtGetChild(0);\n            Node child2 = node.jjtGetChild(1);\n            if (child1 instanceof TypeNode && child2 instanceof TypeNode) {\n                Class<?> type1 = ((TypeNode)child1).getType();\n                Class<?> type2 = ((TypeNode)child2).getType();\n                if (type1 != null && type2 != null) {\n                    // Yeah, String is not numeric, but easiest place to handle\n                    // it, only affects ASTAdditiveExpression\n                    if (String.class.getName().equals(type1.getName()) || String.class.getName().equals(\n                        type2.getName())) {\n                        populateType(typeNode, String.class.getName());\n                    } else if (boolean.class.getName().equals(type1.getName()) || boolean.class.getName().equals(\n                        type2.getName())) {\n                        populateType(typeNode, boolean.class.getName());\n                    } else if (double.class.getName().equals(type1.getName()) || double.class.getName().equals(\n                        type2.getName())) {\n                        populateType(typeNode, double.class.getName());\n                    } else if (float.class.getName().equals(type1.getName()) || float.class.getName().equals(\n                        type2.getName())) {\n                        populateType(typeNode, float.class.getName());\n                    } else if (long.class.getName().equals(type1.getName()) || long.class.getName().equals(\n                        type2.getName())) {\n                        populateType(typeNode, long.class.getName());\n                    } else {\n                        populateType(typeNode, int.class.getName());\n                    }\n                } else if (type1 != null || type2 != null) {\n                    // If one side is known to be a String, then the result is a\n                    // String\n                    // Yeah, String is not numeric, but easiest place to handle\n                    // it, only affects ASTAdditiveExpression\n                    boolean populateString = type1 != null && String.class.getName().equals(type1.getName())\n                        || type2 != null && String.class.getName().equals(type2.getName());\n                    if (populateString) {\n                        populateType(typeNode, String.class.getName());\n                    }\n                }\n            }\n        }\n    }\n\n    private void populateType(TypeNode node, String className) {\n\n        String qualifiedName = className;\n        Class<?> myType = PRIMITIVE_TYPES.get(className);\n        if (myType == null && importedClasses != null) {\n            if (importedClasses.containsKey(className)) {\n                qualifiedName = importedClasses.get(className);\n            } else if (importedClasses.containsValue(className)) {\n                qualifiedName = className;\n            }\n            if (qualifiedName != null) {\n                try {\n                    /*\n                     * TODO - the map right now contains just class names. if we\n                     * use a map of classname/class then we don't have to hit\n                     * the class loader for every type - much faster\n                     */\n                    myType = pmdClassLoader.loadClass(qualifiedName);\n                } catch (ClassNotFoundException e) {\n                    myType = processOnDemand(qualifiedName);\n                } catch (NoClassDefFoundError e) {\n                    myType = processOnDemand(qualifiedName);\n                } catch (LinkageError e) {\n                    myType = processOnDemand(qualifiedName);\n                }\n            }\n        }\n        if (myType == null && qualifiedName != null && qualifiedName.contains(DOT_STRING)) {\n            // try if the last part defines a inner class\n            String qualifiedNameInner = qualifiedName.substring(0,\n                qualifiedName.lastIndexOf(StringAndCharConstants.DOT)) + \"$\"\n                + qualifiedName.substring(qualifiedName.lastIndexOf(StringAndCharConstants.DOT) + 1);\n            try {\n                myType = pmdClassLoader.loadClass(qualifiedNameInner);\n            } catch (Exception e) {\n                // ignored\n            }\n        }\n        if (myType == null && qualifiedName != null && !qualifiedName.contains(DOT_STRING)) {\n            // try again with java.lang....\n            try {\n                myType = pmdClassLoader.loadClass(\"java.lang.\" + qualifiedName);\n            } catch (Exception e) {\n                // ignored\n            }\n        }\n        if (myType != null) {\n            node.setType(myType);\n        }\n    }\n\n    /**\n     * Check whether the supplied class name exists.\n     */\n    @Override\n    public boolean classNameExists(String fullyQualifiedClassName) {\n        try {\n            pmdClassLoader.loadClass(fullyQualifiedClassName);\n            // Class found\n            return true;\n        } catch (ClassNotFoundException e) {\n            return false;\n        } catch (NoClassDefFoundError e) {\n            return false;\n        }\n    }\n\n    @Override\n    public Class<?> loadClass(String fullyQualifiedClassName) {\n        try {\n            return pmdClassLoader.loadClass(fullyQualifiedClassName);\n        } catch (ClassNotFoundException e) {\n            return null;\n        }\n    }\n\n    private Class<?> processOnDemand(String qualifiedName) {\n        for (String entry : importedOnDemand) {\n            try {\n                return pmdClassLoader.loadClass(entry + \".\" + qualifiedName);\n            } catch (Throwable e) {\n            }\n        }\n        return null;\n    }\n\n    private String getClassName(ASTCompilationUnit node) {\n        ASTClassOrInterfaceDeclaration classDecl = node.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class);\n        if (classDecl == null) {\n            // Happens if this compilation unit only contains an\n            // enum\n            return null;\n        }\n        if (node.declarationsAreInDefaultPackage()) {\n            return classDecl.getImage();\n        }\n        ASTPackageDeclaration pkgDecl = node.getPackageDeclaration();\n        importedOnDemand.add(pkgDecl.getPackageNameImage());\n        return pkgDecl.getPackageNameImage() + DOT_STRING + classDecl.getImage();\n    }\n\n    /**\n     * If the outer class wasn't found then we'll get in here\n     */\n    private void populateImports(ASTCompilationUnit node) {\n        List<ASTImportDeclaration> theImportDeclarations = node.findChildrenOfType(ASTImportDeclaration.class);\n\n        importedClasses.putAll(JAVA_LANG);\n\n        // go through the imports\n        for (ASTImportDeclaration anImportDeclaration : theImportDeclarations) {\n            String strPackage = anImportDeclaration.getPackageName();\n            if (anImportDeclaration.isImportOnDemand()) {\n                importedOnDemand.add(strPackage);\n            } else if (!anImportDeclaration.isImportOnDemand()) {\n                String strName = anImportDeclaration.getImportedName();\n                importedClasses.put(strName, strName);\n                importedClasses.put(strName.substring(strPackage.length() + 1), strName);\n            }\n        }\n    }\n\n    private void populateClassName(ASTCompilationUnit node, String className) throws ClassNotFoundException {\n        node.setType(pmdClassLoader.loadClass(className));\n        importedClasses.putAll(pmdClassLoader.getImportedClasses(className));\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/AbstractXpathRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang;\n\nimport com.alibaba.p3c.pmd.I18nResources;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.rule.XPathRule;\n\n/**\n * @author caikang\n * @date 2017/05/25\n */\npublic abstract class AbstractXpathRule extends XPathRule {\n    @Override\n    public void setDescription(String description) {\n        super.setDescription(I18nResources.getMessageWithExceptionHandled(description));\n    }\n\n    @Override\n    public void setMessage(String message) {\n        super.setMessage(I18nResources.getMessageWithExceptionHandled(message));\n    }\n\n    @Override\n    public void addViolationWithMessage(Object data, Node node, String message) {\n        super.addViolationWithMessage(data, node, I18nResources.getMessageWithExceptionHandled(message));\n    }\n\n    @Override\n    public void addViolationWithMessage(Object data, Node node, String message, Object[] args) {\n        super.addViolationWithMessage(data, node,\n            String.format(I18nResources.getMessageWithExceptionHandled(message), args));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/AbstractAliRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.fix.FixClassTypeResolver;\n\nimport net.sourceforge.pmd.RuleContext;\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * re calculate node type\n *\n * @author caikang\n * @date 2016/11/20\n */\npublic abstract class AbstractAliRule extends AbstractJavaRule {\n\n    private static final Map<String, Boolean> TYPE_RESOLVER_MAP = new ConcurrentHashMap<>(16);\n\n    private static final String EMPTY_FILE_NAME = \"n/a\";\n    private static final String DELIMITER = \"-\";\n\n    @Override\n    public Object visit(ASTCompilationUnit node, Object data) {\n        // Each CompilationUnit will be scanned only once by custom type resolver.\n        String sourceCodeFilename = ((RuleContext)data).getSourceCodeFilename();\n\n        // Do type resolve if file name is empty(unit tests).\n        if (StringUtils.isBlank(sourceCodeFilename) || EMPTY_FILE_NAME.equals(sourceCodeFilename)) {\n            resolveType(node, data);\n            return super.visit(node, data);\n        }\n\n        // If file name is not empty, use filename + hashcode to identify a compilation unit.\n        String uniqueId = sourceCodeFilename + DELIMITER + node.hashCode();\n        if (!TYPE_RESOLVER_MAP.containsKey(uniqueId)) {\n            resolveType(node, data);\n            TYPE_RESOLVER_MAP.put(uniqueId, true);\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public void setDescription(String description) {\n        super.setDescription(I18nResources.getMessage(description));\n    }\n\n    @Override\n    public void setMessage(String message) {\n        super.setMessage(I18nResources.getMessageWithExceptionHandled(message));\n    }\n\n    @Override\n    public void addViolationWithMessage(Object data, Node node, String message) {\n        super.addViolationWithMessage(data, node, I18nResources.getMessageWithExceptionHandled(message));\n    }\n\n    @Override\n    public void addViolationWithMessage(Object data, Node node, String message, Object[] args) {\n        super.addViolationWithMessage(data, node,\n            String.format(I18nResources.getMessageWithExceptionHandled(message), args));\n    }\n\n    private void resolveType(ASTCompilationUnit node, Object data) {\n        FixClassTypeResolver classTypeResolver = new FixClassTypeResolver(AbstractAliRule.class.getClassLoader());\n        node.setClassTypeResolver(classTypeResolver);\n        node.jjtAccept(classTypeResolver, data);\n    }\n}\n\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/AbstractPojoRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.util.PojoUtils;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\n\n/**\n * Base class for POJO\n *\n * @author zenghou.fw\n * @date 2016/11/25\n */\npublic abstract class AbstractPojoRule extends AbstractAliRule {\n\n    /**\n     * filter for all POJO class,skip if no POJO.\n     * consider inner class\n     *\n     * @param node compilation unit\n     * @param data rule context\n     * @return result\n     */\n    @Override\n    public Object visit(ASTCompilationUnit node, Object data) {\n        // proceed if contains POJO\n        if (hasPojoInJavaFile(node)) {\n            return super.visit(node, data);\n        }\n        return data;\n    }\n\n    /**\n     * check contains POJO\n     * @param node compilation unit\n     * @return\n     */\n    private boolean hasPojoInJavaFile(ASTCompilationUnit node) {\n        List<ASTClassOrInterfaceDeclaration> klasses = node.findDescendantsOfType(\n                ASTClassOrInterfaceDeclaration.class);\n        for (ASTClassOrInterfaceDeclaration klass : klasses) {\n            if (isPojo(klass)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    protected boolean isPojo(ASTClassOrInterfaceDeclaration node) {\n        return PojoUtils.isPojo(node);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/comment/AbstractAliCommentRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.comment;\n\nimport com.alibaba.p3c.pmd.I18nResources;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.rule.documentation.AbstractCommentRule;\n\n/**\n * @author caikang\n * @date 2017/06/21\n */\npublic class AbstractAliCommentRule extends AbstractCommentRule {\n    @Override\n    public void setDescription(String description) {\n        super.setDescription(I18nResources.getMessageWithExceptionHandled(description));\n    }\n\n    @Override\n    public void setMessage(String message) {\n        super.setMessage(I18nResources.getMessageWithExceptionHandled(message));\n    }\n\n    @Override\n    public void addViolationWithMessage(Object data, Node node, String message) {\n        super.addViolationWithMessage(data, node, I18nResources.getMessageWithExceptionHandled(message));\n    }\n\n    @Override\n    public void addViolationWithMessage(Object data, Node node, String message, Object[] args) {\n        super.addViolationWithMessage(data, node,\n            String.format(I18nResources.getMessageWithExceptionHandled(message), args));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/comment/AbstractMethodOrInterfaceMethodMustUseJavadocRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.comment;\n\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTNameList;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\nimport net.sourceforge.pmd.lang.java.ast.Comment;\nimport net.sourceforge.pmd.lang.java.ast.FormalComment;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Abstract methods (including methods in interface) should be commented by Javadoc.\n * Javadoc should include method instruction, description of parameters, return values and possible exception.\n *\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class AbstractMethodOrInterfaceMethodMustUseJavadocRule extends AbstractAliCommentRule {\n\n    private static final String METHOD_IN_INTERFACE_XPATH =\n        \"./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration\";\n    private static final String METHOD_VARIABLE_DECLARATOR_XPATH\n        = \"./MethodDeclarator/FormalParameters/FormalParameter/VariableDeclaratorId\";\n\n    private static final String MESSAGE_KEY_PREFIX\n        = \"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg\";\n\n    private static final Pattern EMPTY_CONTENT_PATTERN = Pattern.compile(\"[/*\\\\n\\\\r\\\\s]+(@.*)?\", Pattern.DOTALL);\n    private static final Pattern RETURN_PATTERN = Pattern.compile(\".*@return.*\", Pattern.DOTALL);\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration decl, Object data) {\n        if (decl.isAbstract()) {\n            List<ASTMethodDeclaration> methods = decl.findDescendantsOfType(ASTMethodDeclaration.class);\n            for (ASTMethodDeclaration method : methods) {\n                if (!method.isAbstract()) {\n                    continue;\n                }\n                Comment comment = method.comment();\n                if (null == comment || !(comment instanceof FormalComment)) {\n                    ViolationUtils.addViolationWithPrecisePosition(this, method, data,\n                        I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".abstract\",\n                            method.getMethodName()));\n                } else {\n                    this.checkMethodCommentFormat(method, data);\n                }\n            }\n        }\n        if (!decl.isInterface()) {\n            return super.visit(decl, data);\n        }\n        List<Node> methodNodes;\n        try {\n            methodNodes = decl.findChildNodesWithXPath(METHOD_IN_INTERFACE_XPATH);\n        } catch (JaxenException e) {\n            throw new RuntimeException(\"XPath expression \" + METHOD_IN_INTERFACE_XPATH\n                + \" failed: \" + e.getLocalizedMessage(), e);\n        }\n\n        for (Node node : methodNodes) {\n            ASTMethodDeclaration method = (ASTMethodDeclaration)node;\n            Comment comment = method.comment();\n            if (null == comment || !(comment instanceof FormalComment)) {\n                ViolationUtils.addViolationWithPrecisePosition(this, method, data,\n                    I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".interface\",\n                        method.getMethodName()));\n            } else {\n                this.checkMethodCommentFormat(method, data);\n            }\n        }\n        return super.visit(decl, data);\n    }\n\n    public void checkMethodCommentFormat(ASTMethodDeclaration method, Object data) {\n        Comment comment = method.comment();\n        String commentContent = comment.getImage();\n\n        // method instruction\n        if (EMPTY_CONTENT_PATTERN.matcher(commentContent).matches()) {\n            ViolationUtils.addViolationWithPrecisePosition(this, method, data,\n                I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".desc\",\n                    method.getMethodName()));\n        }\n\n        // description of parameters\n        List<Node> variableDeclaratorIds;\n        try {\n            variableDeclaratorIds = method.findChildNodesWithXPath(METHOD_VARIABLE_DECLARATOR_XPATH);\n        } catch (JaxenException e) {\n            throw new RuntimeException(\n                \"XPath expression \" + METHOD_VARIABLE_DECLARATOR_XPATH + \" failed: \" + e.getLocalizedMessage(), e);\n        }\n\n        for (Node variableDeclaratorId : variableDeclaratorIds) {\n            ASTVariableDeclaratorId param = (ASTVariableDeclaratorId)variableDeclaratorId;\n            String paramName = param.getImage();\n            Pattern paramNamePattern = Pattern.compile(\".*@param\\\\s+\" + paramName + \".*\", Pattern.DOTALL);\n\n            if (!paramNamePattern.matcher(commentContent).matches()) {\n                ViolationUtils.addViolationWithPrecisePosition(this, method, data,\n                    I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".parameter\",\n                        method.getMethodName(), paramName));\n            }\n        }\n\n        // return values\n        if (!method.isVoid() && !RETURN_PATTERN.matcher(commentContent).matches()) {\n\n            ViolationUtils.addViolationWithPrecisePosition(this, method, data,\n                I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".return\",\n                    method.getMethodName()));\n        }\n\n        // possible exception\n        ASTNameList nameList = method.getThrows();\n        if (null != nameList) {\n            List<ASTName> exceptions = nameList.findDescendantsOfType(ASTName.class);\n            for (ASTName exception : exceptions) {\n                String exceptionName = exception.getImage();\n                Pattern exceptionPattern = Pattern.compile(\".*@throws\\\\s+\"\n                    + exceptionName + \".*\", Pattern.DOTALL);\n\n                if (!exceptionPattern.matcher(commentContent).matches()) {\n                    ViolationUtils.addViolationWithPrecisePosition(this, method, data,\n                        I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".exception\",\n                            method.getMethodName(), exceptionName));\n                }\n            }\n        }\n    }\n\n    @Override\n    public Object visit(ASTCompilationUnit cUnit, Object data) {\n        assignCommentsToDeclarations(cUnit);\n        return super.visit(cUnit, data);\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/comment/AvoidCommentBehindStatementRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.comment;\n\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeSortUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTEnumConstant;\nimport net.sourceforge.pmd.lang.java.ast.ASTExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;\nimport net.sourceforge.pmd.lang.java.ast.Comment;\n\n/**\n * [Mandatory] Single line comments in a method should be put above the code to be commented, by using // and\n * multiple lines by using \\/* *\\/. Alignment for comments should be noticed carefully.\n *\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class AvoidCommentBehindStatementRule extends AbstractAliCommentRule {\n\n    @Override\n    public Object visit(ASTCompilationUnit cUnit, Object data) {\n        SortedMap<Integer, Node> itemsByLineNumber = orderedCommentsAndExpressions(cUnit);\n        AbstractJavaNode lastNode = null;\n\n        for (Entry<Integer, Node> entry : itemsByLineNumber.entrySet()) {\n            Node value = entry.getValue();\n            if (value instanceof AbstractJavaNode) {\n                lastNode = (AbstractJavaNode)value;\n            } else if (value instanceof Comment) {\n                Comment comment = (Comment)value;\n                if (lastNode != null && (comment.getBeginLine() == lastNode.getBeginLine())\n                    && (comment.getEndColumn() > lastNode.getBeginColumn())) {\n                    addViolationWithMessage(data, lastNode,\n                        I18nResources.getMessage(\"java.comment.AvoidCommentBehindStatementRule.violation.msg\"),\n                        comment.getBeginLine(), comment.getEndLine());\n                }\n            }\n        }\n\n        return super.visit(cUnit, data);\n    }\n\n    /**\n     * Check comments behind nodes.\n     *\n     * @param cUnit compilation unit\n     * @return sorted comments and expressions\n     */\n    protected SortedMap<Integer, Node> orderedCommentsAndExpressions(ASTCompilationUnit cUnit) {\n\n        SortedMap<Integer, Node> itemsByLineNumber = new TreeMap<>();\n\n        // expression nodes\n        List<ASTExpression> expressionNodes = cUnit.findDescendantsOfType(ASTExpression.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, expressionNodes);\n\n        // filed declaration nodes\n        List<ASTFieldDeclaration> fieldNodes =\n            cUnit.findDescendantsOfType(ASTFieldDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, fieldNodes);\n\n        // enum constant nodes\n        List<ASTEnumConstant> enumConstantNodes =\n            cUnit.findDescendantsOfType(ASTEnumConstant.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, enumConstantNodes);\n\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, cUnit.getComments());\n\n        return itemsByLineNumber;\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/comment/ClassMustHaveAuthorRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.comment;\n\nimport java.util.List;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\nimport java.util.regex.Pattern;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;\nimport net.sourceforge.pmd.lang.java.ast.Comment;\n\n/**\n * [Mandatory] Every class should include information of author(s) and date.\n *\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class ClassMustHaveAuthorRule extends AbstractAliCommentRule {\n\n    private static final Pattern AUTHOR_PATTERN = Pattern.compile(\".*@[Aa]uthor.*\",\n        Pattern.DOTALL | Pattern.CASE_INSENSITIVE);\n\n    private static final String MESSAGE_KEY_PREFIX = \"java.comment.ClassMustHaveAuthorRule.violation.msg\";\n\n    /**\n     * Immediately return after visiting class/interface/enum/annotation,\n     * so that we don't need to deal with inner class/interface/enum/annotation declarations.\n     *\n     * @param decl node\n     * @param data ruleContext\n     * @return result\n     */\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration decl, Object data) {\n        // If a CompilationUnit has multi class definition, only the public one will be checked.\n        if (decl.isPublic()) {\n            checkAuthorComment(decl, data);\n        }\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTEnumDeclaration decl, Object data) {\n        // Exclude inner enum\n        if (!decl.isPublic()) {\n            return super.visit(decl, data);\n        }\n\n        // Inner enum should have author tag in outer class.\n        ASTClassOrInterfaceDeclaration parent = decl.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);\n        if (parent != null) {\n            return super.visit(decl, data);\n        }\n\n        checkAuthorComment(decl, data);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTAnnotationTypeDeclaration decl, Object data) {\n        checkAuthorComment(decl, data);\n        return data;\n    }\n\n    @Override\n    public Object visit(ASTCompilationUnit cUnit, Object data) {\n        assignCommentsToDeclarations(cUnit);\n\n        return super.visit(cUnit, data);\n    }\n\n    @Override\n    protected SortedMap<Integer, Node> orderedCommentsAndDeclarations(ASTCompilationUnit cUnit) {\n        SortedMap<Integer, Node> itemsByLineNumber = new TreeMap<>();\n\n        List<ASTClassOrInterfaceDeclaration> packageDecl = cUnit\n            .findDescendantsOfType(ASTClassOrInterfaceDeclaration.class);\n        addDeclarations(itemsByLineNumber, packageDecl);\n\n        List<ASTEnumDeclaration> enumDecl = cUnit.findDescendantsOfType(ASTEnumDeclaration.class);\n        addDeclarations(itemsByLineNumber, enumDecl);\n\n        List<ASTAnnotationTypeDeclaration> annotationDecl = cUnit\n            .findDescendantsOfType(ASTAnnotationTypeDeclaration.class);\n        addDeclarations(itemsByLineNumber, annotationDecl);\n\n        addDeclarations(itemsByLineNumber, cUnit.getComments());\n\n        return itemsByLineNumber;\n    }\n\n    private void addDeclarations(SortedMap<Integer, Node> map, List<? extends Node> nodes) {\n        for (Node node : nodes) {\n            map.put((node.getBeginLine() << 16) + node.getBeginColumn(), node);\n        }\n    }\n\n    /**\n     * Check if node's comment contains author tag.\n     *\n     * @param decl node\n     * @param data ruleContext\n     */\n    public void checkAuthorComment(AbstractJavaNode decl, Object data) {\n        Comment comment = decl.comment();\n        if (null == comment) {\n            ViolationUtils.addViolationWithPrecisePosition(this, decl, data,\n                I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".comment\", decl.getImage()));\n        } else {\n            String commentContent = comment.getImage();\n            boolean hasAuthor = AUTHOR_PATTERN.matcher(commentContent).matches();\n            if (!hasAuthor) {\n                ViolationUtils.addViolationWithPrecisePosition(this, decl, data,\n                    I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".author\", decl.getImage()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/comment/CommentsMustBeJavadocFormatRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.comment;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeSortUtils;\n\nimport com.alibaba.p3c.pmd.lang.java.util.VariableUtils;\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTAnnotation;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;\nimport net.sourceforge.pmd.lang.java.ast.Comment;\nimport net.sourceforge.pmd.lang.java.ast.MultiLineComment;\nimport net.sourceforge.pmd.lang.java.ast.SingleLineComment;\nimport net.sourceforge.pmd.lang.java.ast.Token;\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * [Mandatory] Javadoc should be used for classes, class variables and methods.\n * The format should be '\\/** comment *\\/', rather than '// xxx'.\n *\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class CommentsMustBeJavadocFormatRule extends AbstractAliCommentRule {\n\n    private static final String MESSAGE_KEY_PREFIX = \"java.comment.CommentsMustBeJavadocFormatRule.violation.msg\";\n\n    @Override\n    public Object visit(final ASTClassOrInterfaceDeclaration decl, Object data) {\n        checkComment(decl, data, () -> I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".class\",\n            decl.getImage()));\n        return super.visit(decl, data);\n    }\n\n    @Override\n    public Object visit(final ASTConstructorDeclaration decl, Object data) {\n        checkComment(decl, data, () -> {\n            String constructorName = ((Token)decl.jjtGetFirstToken()).image;\n            if (decl.getFormalParameters().getParameterCount() == 0) {\n                return I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".constructor.default\",\n                    constructorName);\n            }\n            List<ASTFormalParameter> formalParameters = decl.getFormalParameters()\n                .findChildrenOfType(ASTFormalParameter.class);\n            List<String> strings = new ArrayList<>(formalParameters.size());\n\n            for (ASTFormalParameter formalParameter : formalParameters) {\n                strings.add(formalParameter.jjtGetFirstToken().toString() + \" \"\n                    + formalParameter.jjtGetLastToken().toString());\n            }\n            return I18nResources\n                .getMessage(MESSAGE_KEY_PREFIX + \".constructor.parameter\",\n                    constructorName,\n                    StringUtils.join(strings, \",\"));\n        });\n        return super.visit(decl, data);\n    }\n\n    @Override\n    public Object visit(final ASTMethodDeclaration decl, Object data) {\n        checkComment(decl, data, () -> I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".method\",\n            decl.getMethodName()));\n        return super.visit(decl, data);\n    }\n\n    @Override\n    public Object visit(final ASTFieldDeclaration decl, Object data) {\n        checkComment(decl, data, () -> I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".field\",\n            VariableUtils.getVariableName(decl)));\n        return super.visit(decl, data);\n    }\n\n    @Override\n    public Object visit(final ASTEnumDeclaration decl, Object data) {\n        checkComment(decl, data, () -> I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".enum\",\n            decl.getImage()));\n        return super.visit(decl, data);\n    }\n\n    @Override\n    public Object visit(ASTCompilationUnit cUnit, Object data) {\n        assignCommentsToDeclarations(cUnit);\n\n        return super.visit(cUnit, data);\n    }\n\n    private void checkComment(AbstractJavaAccessNode decl, Object data, MessageMaker maker) {\n        Comment comment = decl.comment();\n        if (comment instanceof SingleLineComment || comment instanceof MultiLineComment) {\n            addViolationWithMessage(data, decl,\n                maker.make(), comment.getBeginLine(), comment.getEndLine());\n        }\n    }\n\n    @Override\n    protected void assignCommentsToDeclarations(ASTCompilationUnit cUnit) {\n\n        SortedMap<Integer, Node> itemsByLineNumber = orderedComments(cUnit);\n        Comment lastComment = null;\n        AbstractJavaNode lastNode = null;\n\n        for (Entry<Integer, Node> entry : itemsByLineNumber.entrySet()) {\n            Node value = entry.getValue();\n\n            if (value instanceof AbstractJavaNode) {\n                AbstractJavaNode node = (AbstractJavaNode)value;\n\n                // skip annotation node, we will deal with it later.\n                if (node instanceof ASTAnnotation) {\n                    continue;\n                }\n\n                // Check if comment is one line above class, field, method.\n                if (lastComment != null && isCommentOneLineBefore(itemsByLineNumber, lastComment, lastNode, node)) {\n                    node.comment(lastComment);\n                    lastComment = null;\n                }\n\n                lastNode = node;\n            } else if (value instanceof Comment) {\n                lastComment = (Comment)value;\n            }\n        }\n    }\n\n    protected SortedMap<Integer, Node> orderedComments(ASTCompilationUnit cUnit) {\n\n        SortedMap<Integer, Node> itemsByLineNumber = new TreeMap<>();\n\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, cUnit.getComments());\n\n        List<ASTAnnotation> annotations = cUnit.findDescendantsOfType(ASTAnnotation.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, annotations);\n\n        List<ASTClassOrInterfaceDeclaration> classDecl =\n            cUnit.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, classDecl);\n\n        List<ASTFieldDeclaration> fields = cUnit.findDescendantsOfType(ASTFieldDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, fields);\n\n        List<ASTMethodDeclaration> methods = cUnit.findDescendantsOfType(ASTMethodDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, methods);\n\n        List<ASTConstructorDeclaration> constructors = cUnit.findDescendantsOfType(ASTConstructorDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, constructors);\n\n        List<ASTEnumDeclaration> enumDecl = cUnit.findDescendantsOfType(ASTEnumDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, enumDecl);\n\n        return itemsByLineNumber;\n    }\n\n    private boolean isCommentOneLineBefore(SortedMap<Integer, Node> items, Comment lastComment, Node lastNode, Node node) {\n        ASTClassOrInterfaceBodyDeclaration parentClass =\n            node.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class);\n\n        // Skip comments inside inner class.\n        if (parentClass != null && parentClass.isAnonymousInnerClass()) {\n            return false;\n        }\n\n        // Skip comments behind nodes.\n        if (lastNode != null && lastNode.getEndLine() == lastComment.getEndLine()) {\n            return false;\n        }\n\n        // check if there is nothing in the middle except annotations.\n        SortedMap<Integer, Node> subMap = items.subMap(NodeSortUtils.generateIndex(lastComment),\n            NodeSortUtils.generateIndex(node));\n        Iterator<Entry<Integer, Node>> iter = subMap.entrySet().iterator();\n\n        // skip the first comment node.\n        iter.next();\n        int lastEndLine = lastComment.getEndLine();\n\n        while (iter.hasNext()) {\n            Entry<Integer, Node> entry = iter.next();\n            Node value = entry.getValue();\n\n            // only annotation node is allowed between comment and node.\n            if (!(value instanceof ASTAnnotation)) {\n                return false;\n            }\n\n            // allow annotation node after comment.\n            if (lastEndLine + 1 == value.getBeginLine()) {\n                lastEndLine = value.getEndLine();\n            }\n        }\n\n        return lastEndLine + 1 == node.getBeginLine();\n    }\n\n    /**\n     * Generate rule violation message.\n     */\n    interface MessageMaker {\n        /**\n         * Generate violation message.\n         *\n         * @return message\n         */\n        String make();\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/comment/EnumConstantsMustHaveCommentRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.comment;\n\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeSortUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTEnumConstant;\nimport net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;\n\n/**\n * [Mandatory] All enumeration type fields should be commented as Javadoc style.\n *\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class EnumConstantsMustHaveCommentRule extends AbstractAliCommentRule {\n\n    @Override\n    public Object visit(ASTCompilationUnit cUnit, Object data) {\n        SortedMap<Integer, Node> itemsByLineNumber = this.orderedCommentsAndEnumDeclarations(cUnit);\n\n        // Check comments between ASTEnumDeclaration and ASTEnumConstant.\n        boolean isPreviousEnumDecl = false;\n\n        for (Entry<Integer, Node> entry : itemsByLineNumber.entrySet()) {\n            Node value = entry.getValue();\n\n            if (value instanceof ASTEnumDeclaration) {\n                isPreviousEnumDecl = true;\n            } else if (value instanceof ASTEnumConstant && isPreviousEnumDecl) {\n                Node enumBody = value.jjtGetParent();\n                Node enumDeclaration = enumBody.jjtGetParent();\n                addViolationWithMessage(data, enumBody,\n                    I18nResources.getMessage(\"java.comment.EnumConstantsMustHaveCommentRule.violation.msg\",\n                        enumDeclaration.getImage()));\n                isPreviousEnumDecl = false;\n            } else {\n                isPreviousEnumDecl = false;\n            }\n        }\n\n        return super.visit(cUnit, data);\n    }\n\n    private SortedMap<Integer, Node> orderedCommentsAndEnumDeclarations(ASTCompilationUnit cUnit) {\n        SortedMap<Integer, Node> itemsByLineNumber = new TreeMap<>();\n\n        List<ASTEnumDeclaration> enumDecl = cUnit.findDescendantsOfType(ASTEnumDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, enumDecl);\n\n        List<ASTEnumConstant> contantDecl = cUnit.findDescendantsOfType(ASTEnumConstant.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, contantDecl);\n\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, cUnit.getComments());\n\n        return itemsByLineNumber;\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/comment/RemoveCommentedCodeRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.comment;\n\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\nimport java.util.regex.Pattern;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeSortUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.Comment;\nimport net.sourceforge.pmd.lang.java.ast.JavaNode;\n\n/**\n * [Recommended] Codes or configuration that is noticed to be obsoleted should be resolutely removed from projects.\n *\n * @author keriezhang\n * @date 2017/04/14\n */\npublic class RemoveCommentedCodeRule extends AbstractAliCommentRule {\n\n    private static final Pattern SUPPRESS_PATTERN = Pattern.compile(\"\\\\s*///.*\", Pattern.DOTALL);\n\n    private static final Pattern PRE_TAG_PATTERN = Pattern.compile(\".*<pre>.*\", Pattern.DOTALL);\n\n    private static final Pattern IMPORT_PATTERN = Pattern.compile(\".*import\\\\s(static\\\\s)?(\\\\w*\\\\.)*\\\\w*;.*\",\n        Pattern.DOTALL);\n\n    private static final Pattern FIELD_PATTERN = Pattern.compile(\".*private\\\\s+(\\\\w*)\\\\s+(\\\\w*);.*\", Pattern.DOTALL);\n\n    private static final Pattern METHOD_PATTERN = Pattern.compile(\n        \".*(public|protected|private)\\\\s+\\\\w+\\\\s+\\\\w+\\\\(.*\\\\)\\\\s+\\\\{.*\", Pattern.DOTALL);\n\n    /**\n     * If string matches format \".xxx(.*);\\n\", then mark it as code.\n     */\n    private static final Pattern STATEMENT_PATTERN = Pattern.compile(\".*\\\\.\\\\w+\\\\(.*\\\\);\\n.*\", Pattern.DOTALL);\n\n    @Override\n    public Object visit(ASTCompilationUnit cUnit, Object data) {\n        checkCommentsBetweenDeclarations(cUnit, data);\n\n        return super.visit(cUnit, data);\n    }\n\n    protected void checkCommentsBetweenDeclarations(ASTCompilationUnit cUnit, Object data) {\n\n        SortedMap<Integer, Node> itemsByLineNumber = orderedCommentsAndDeclarations(cUnit);\n        Comment lastComment = null;\n        boolean suppressWarning = false;\n        CommentPatternEnum commentPattern = CommentPatternEnum.NONE;\n\n        for (Entry<Integer, Node> entry : itemsByLineNumber.entrySet()) {\n            Node value = entry.getValue();\n\n            if (value instanceof JavaNode) {\n                JavaNode node = (JavaNode)value;\n\n                // add violation on the node after comment.\n                if (lastComment != null && isCommentBefore(lastComment, node)) {\n                    // find code comment, but need filter some case.\n                    if (!CommentPatternEnum.NONE.equals(commentPattern)) {\n                        // check statement pattern only in method\n                        boolean statementOutsideMethod = CommentPatternEnum.STATEMENT.equals(commentPattern)\n                            && !(node instanceof ASTBlockStatement);\n                        if (!statementOutsideMethod) {\n                            addViolationWithMessage(data, node, getMessage(),\n                                lastComment.getBeginLine(),\n                                lastComment.getEndLine());\n                        }\n                    }\n                    lastComment = null;\n                }\n\n                // reset data after each node.\n                suppressWarning = false;\n                commentPattern = CommentPatternEnum.NONE;\n\n            } else if (value instanceof Comment) {\n                lastComment = (Comment)value;\n                String content = lastComment.getImage();\n\n                if (!suppressWarning) {\n                    suppressWarning = SUPPRESS_PATTERN.matcher(content).matches();\n                }\n\n                if (!suppressWarning && CommentPatternEnum.NONE.equals(commentPattern)) {\n                    commentPattern = this.scanCommentedCode(content);\n                }\n            }\n        }\n    }\n\n    /**\n     * Common Situations, check in following order:\n     * 1. commented import\n     * 2. commented field\n     * 3. commented method\n     * 4. commented statement\n     *\n     * @param content comment content\n     * @return check result\n     */\n    protected CommentPatternEnum scanCommentedCode(String content) {\n        CommentPatternEnum pattern = CommentPatternEnum.NONE;\n\n        // Skip comment which contains pre tag.\n        if (PRE_TAG_PATTERN.matcher(content).matches()) {\n            return pattern;\n        }\n\n        if (IMPORT_PATTERN.matcher(content).matches()) {\n            pattern = CommentPatternEnum.IMPORT;\n        } else if (FIELD_PATTERN.matcher(content).matches()) {\n            pattern = CommentPatternEnum.FIELD;\n        } else if (METHOD_PATTERN.matcher(content).matches()) {\n            pattern = CommentPatternEnum.METHOD;\n        } else if (STATEMENT_PATTERN.matcher(content).matches()) {\n            pattern = CommentPatternEnum.STATEMENT;\n        }\n\n        return pattern;\n    }\n\n    @Override\n    protected SortedMap<Integer, Node> orderedCommentsAndDeclarations(ASTCompilationUnit cUnit) {\n        SortedMap<Integer, Node> itemsByLineNumber = new TreeMap<>();\n\n        List<ASTImportDeclaration> importDecl = cUnit\n            .findDescendantsOfType(ASTImportDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, importDecl);\n\n        List<ASTClassOrInterfaceDeclaration> classDecl = cUnit\n            .findDescendantsOfType(ASTClassOrInterfaceDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, classDecl);\n\n        List<ASTFieldDeclaration> fields = cUnit.findDescendantsOfType(ASTFieldDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, fields);\n\n        List<ASTMethodDeclaration> methods = cUnit.findDescendantsOfType(ASTMethodDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, methods);\n\n        List<ASTConstructorDeclaration> constructors = cUnit.findDescendantsOfType(ASTConstructorDeclaration.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, constructors);\n\n        List<ASTBlockStatement> blockStatements = cUnit.findDescendantsOfType(ASTBlockStatement.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, blockStatements);\n\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, cUnit.getComments());\n\n        return itemsByLineNumber;\n    }\n\n    private boolean isCommentBefore(Comment n1, Node n2) {\n        return n1.getEndLine() < n2.getBeginLine() || n1.getEndLine() == n2.getBeginLine()\n            && n1.getEndColumn() < n2.getBeginColumn();\n    }\n\n    enum CommentPatternEnum {\n        /**\n         * comment has code pattern\n         */\n        IMPORT,\n        FIELD,\n        METHOD,\n        STATEMENT,\n        NONE\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/AvoidCallStaticSimpleDateFormatRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport java.text.SimpleDateFormat;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.Stack;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.dfa.DataFlowNode;\nimport net.sourceforge.pmd.lang.dfa.StartOrEndDataFlowNode;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;\nimport net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;\nimport net.sourceforge.pmd.lang.java.ast.Token;\n\nimport static com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils.isLockNode;\nimport static com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils.isLockStatementExpression;\nimport static com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils.isUnLockStatementExpression;\n\n/**\n * [Mandatory] SimpleDataFormat is unsafe, do not define it as a static variable.\n * If have to, lock or DateUtils class must be used.\n *\n * @author caikang\n * @date 2016/11/25\n */\npublic class AvoidCallStaticSimpleDateFormatRule extends AbstractAliRule {\n    private static final String FORMAT_METHOD_NAME = \"format\";\n\n    @Override\n    public Object visit(ASTMethodDeclaration node, Object data) {\n        if (node.isSynchronized()) {\n            return super.visit(node, data);\n        }\n\n        handleMethod(node, data);\n        return super.visit(node, data);\n    }\n\n    private void handleMethod(ASTMethodDeclaration methodDeclaration, Object data) {\n        DataFlowNode dataFlowNode = methodDeclaration.getDataFlowNode();\n        if (dataFlowNode == null || dataFlowNode.getFlow() == null) {\n            return;\n        }\n        // records of violations,lock block excepted\n        Stack<Node> stack = new Stack<>();\n        Set<String> localSimpleDateFormatNames = new HashSet<>();\n        for (DataFlowNode flowNode : dataFlowNode.getFlow()) {\n            handleFlowNode(stack, localSimpleDateFormatNames, flowNode);\n        }\n        while (!stack.isEmpty()) {\n            Node node = stack.pop();\n            if (node instanceof ASTPrimaryExpression) {\n                addViolationWithMessage(data, node,\n                    \"java.concurrent.AvoidCallStaticSimpleDateFormatRule.violation.msg\",\n                    new Object[] {getExpressName((ASTPrimaryExpression)node)});\n            }\n        }\n    }\n\n    private void handleFlowNode(Stack<Node> stack, Set<String> localSimpleDateFormatNames, DataFlowNode flowNode) {\n        if (flowNode instanceof StartOrEndDataFlowNode || flowNode.getNode() instanceof ASTMethodDeclaration) {\n            return;\n        }\n        // collect local variables of type SimpleDateFormat if match,then return\n        if (flowNode.getNode() instanceof ASTVariableDeclarator) {\n            ASTVariableDeclarator variableDeclarator = (ASTVariableDeclarator)flowNode.getNode();\n            if (variableDeclarator.getType() == SimpleDateFormat.class) {\n                ASTVariableDeclaratorId variableDeclaratorId =\n                    variableDeclarator.getFirstChildOfType(ASTVariableDeclaratorId.class);\n                localSimpleDateFormatNames.add(variableDeclaratorId.getImage());\n                return;\n            }\n        }\n\n        if (flowNode.getNode() instanceof ASTStatementExpression) {\n            ASTStatementExpression statementExpression = (ASTStatementExpression)flowNode.getNode();\n            if (isLockStatementExpression(statementExpression)) {\n                // add lock node\n                stack.push(flowNode.getNode());\n                return;\n            }\n\n            if (isUnLockStatementExpression(statementExpression)) {\n                // remove element in lock block\n                while (!stack.isEmpty()) {\n                    Node node = stack.pop();\n                    if (isLockNode(node)) {\n                        break;\n                    }\n                }\n                return;\n            }\n        }\n        AbstractJavaNode javaNode = (AbstractJavaNode)flowNode.getNode();\n        ASTPrimaryExpression flowPrimaryExpression = javaNode.getFirstDescendantOfType(ASTPrimaryExpression.class);\n        if (flowPrimaryExpression == null) {\n            return;\n        }\n        if (flowPrimaryExpression.getFirstParentOfType(ASTSynchronizedStatement.class) != null) {\n            return;\n        }\n        if (!isStaticSimpleDateFormatCall(flowPrimaryExpression, localSimpleDateFormatNames)) {\n            return;\n        }\n        // add violation element (include those in lock block,until we meet unlock block,we can remove them)\n        stack.push(flowPrimaryExpression);\n    }\n\n    private String getExpressName(ASTPrimaryExpression primaryExpression) {\n        ASTName name = primaryExpression.getFirstDescendantOfType(ASTName.class);\n        return name.getImage();\n    }\n\n    private boolean isStaticSimpleDateFormatCall(\n        ASTPrimaryExpression primaryExpression,\n        Set<String> localSimpleDateFormatNames\n    ) {\n        if (primaryExpression.jjtGetNumChildren() == 0) {\n            return false;\n        }\n        ASTName name = primaryExpression.getFirstDescendantOfType(ASTName.class);\n        if (name == null || name.getType() != SimpleDateFormat.class) {\n            return false;\n        }\n        if (name.getNameDeclaration() == null || name.getNameDeclaration().getName() == null) {\n            return false;\n        }\n        if (localSimpleDateFormatNames.contains(name.getNameDeclaration().getName())) {\n            return false;\n        }\n        ASTPrimaryPrefix primaryPrefix = (ASTPrimaryPrefix)primaryExpression.jjtGetChild(0);\n        if (primaryPrefix.getType() != SimpleDateFormat.class) {\n            return false;\n        }\n\n        Token token = (Token)primaryPrefix.jjtGetLastToken();\n        return FORMAT_METHOD_NAME.equals(token.image);\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/AvoidConcurrentCompetitionRandomRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport java.util.List;\nimport java.util.Random;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.VariableUtils;\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTExtendsList;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;\nimport org.jaxen.JaxenException;\n\n/**\n * 6.13 [Recommended] Avoid using Random instance by multiple threads.\n * Although it is safe to share this instance, competition on the same seed will damage performance.\n * Note: Random instance includes instances of java.util.Random and Math.random().\n *\n * @author caikang\n * @date 2017/03/29\n */\npublic class AvoidConcurrentCompetitionRandomRule extends AbstractAliRule {\n\n    private static final String XPATH_TPL = \"//StatementExpression/PrimaryExpression\"\n        + \"/PrimaryPrefix/Name[starts-with(@Image,'%s.')]\";\n\n    private static final String MATH_RANDOM_METHOD = \".random\";\n\n    private static final String MESSAGE_KEY_PREFIX = \"java.concurrent.AvoidConcurrentCompetitionRandomRule\";\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        ASTExtendsList extendsList = node.getFirstChildOfType(ASTExtendsList.class);\n        if (extendsList == null) {\n            return super.visit(node, data);\n        }\n        if (!hasThread(extendsList)) {\n            return super.visit(node, data);\n        }\n        List<ASTMethodDeclaration> methodDeclarations = node.findDescendantsOfType(ASTMethodDeclaration.class);\n        if (methodDeclarations == null || methodDeclarations.isEmpty()) {\n            return super.visit(node, data);\n        }\n        checkMathRandom(methodDeclarations, data);\n\n        List<ASTFieldDeclaration> fieldDeclarations = node.findDescendantsOfType(ASTFieldDeclaration.class);\n        if (fieldDeclarations == null || fieldDeclarations.isEmpty()) {\n            return super.visit(node, data);\n        }\n        for (ASTFieldDeclaration fieldDeclaration : fieldDeclarations) {\n            if (NodeUtils.getNodeType(fieldDeclaration) == Random.class\n                && fieldDeclaration.isStatic()) {\n                checkRandom(fieldDeclaration, methodDeclarations, data);\n            }\n        }\n        return super.visit(node, data);\n    }\n\n    private void checkMathRandom(List<ASTMethodDeclaration> methodDeclarations, Object data) {\n        for (ASTMethodDeclaration methodDeclaration : methodDeclarations) {\n            List<ASTPrimaryPrefix> primaryPrefixes\n                = methodDeclaration.findDescendantsOfType(ASTPrimaryPrefix.class);\n            if (primaryPrefixes == null || primaryPrefixes.isEmpty()) {\n                continue;\n            }\n            for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) {\n                if (primaryPrefix.getType() != Math.class) {\n                    continue;\n                }\n                ASTName name = primaryPrefix.getFirstChildOfType(ASTName.class);\n                if (name == null || name.getImage() == null || !name.getImage().endsWith(MATH_RANDOM_METHOD)) {\n                    continue;\n                }\n                addViolationWithMessage(data, primaryPrefix,\n                    MESSAGE_KEY_PREFIX + \".violation.msg.math.random\");\n            }\n        }\n    }\n\n    private void checkRandom(ASTFieldDeclaration fieldDeclaration, List<ASTMethodDeclaration> methodDeclarations,\n        Object data) {\n        for (ASTMethodDeclaration methodDeclaration : methodDeclarations) {\n            try {\n                List<Node> nodes = methodDeclaration.findChildNodesWithXPath(String.format(XPATH_TPL,\n                    VariableUtils.getVariableName(fieldDeclaration)));\n                if (nodes == null || nodes.isEmpty()) {\n                    continue;\n                }\n                for (Node rvNode : nodes) {\n                    addViolationWithMessage(data, rvNode,\n                        MESSAGE_KEY_PREFIX + \".violation.msg.random\",\n                        new Object[] {rvNode.getImage()});\n                }\n            } catch (JaxenException ignore) {\n            }\n        }\n    }\n\n    private boolean hasThread(ASTExtendsList extendsList) {\n        List<ASTClassOrInterfaceType> typeList = extendsList.findChildrenOfType(ASTClassOrInterfaceType.class);\n        if (typeList == null || typeList.isEmpty()) {\n            return false;\n        }\n        for (ASTClassOrInterfaceType type : typeList) {\n            if (type.getType() == Thread.class) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/AvoidManuallyCreateThreadRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport java.util.List;\nimport java.util.concurrent.ThreadFactory;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;\nimport net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;\nimport net.sourceforge.pmd.lang.java.ast.ASTImplementsList;\nimport net.sourceforge.pmd.lang.java.ast.ASTInitializer;\nimport net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTResultType;\nimport net.sourceforge.pmd.lang.java.ast.ASTType;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.Token;\n\n/**\n * [Mandatory] Threads should be provided by thread pools. Explicitly creating threads is not allowed.\n * Note: Using thread pool can reduce the time of creating and destroying thread and save system resource.\n * If we do not use thread pools, lots of similar threads will be created which lead to\n * \"running out of memory\" or over-switching problems.\n *\n * Detection rule\n * New Thread can only be created in ThreadFactory.newThread method,as Runtime.getRuntime().addShutdownHook() parameter,\n * or in static block\n *\n * @author caikang\n * @date 2016/11/15\n * @see ThreadShouldSetNameRule\n */\npublic class AvoidManuallyCreateThreadRule extends AbstractAliRule {\n\n    private static final String METHOD_NEW_THREAD = \"newThread\";\n\n    @Override\n    public Object visit(ASTAllocationExpression node, Object data) {\n        if (node.getType() != Thread.class) {\n            return super.visit(node, data);\n        }\n        if (isAddShutdownHook(node) || isInStaticInitializer(node)) {\n            return super.visit(node, data);\n        }\n        //Allocation in lambda block is ignored\n        if (node.getFirstParentOfType(ASTLambdaExpression.class) != null) {\n            return super.visit(node, data);\n        }\n        ASTFieldDeclaration fieldDeclaration = node.getFirstParentOfType(ASTFieldDeclaration.class);\n        //field declaration with thread allocated\n        if (fieldDeclaration != null && NodeUtils.getNodeType(fieldDeclaration) == Thread.class) {\n            return addViolationAndReturn(node, data);\n        }\n        //Declare thread factory field use lambda\n        if (node.getDataFlowNode() == null && node.getFirstParentOfType(ASTLambdaExpression.class) != null) {\n            if (fieldDeclaration == null || NodeUtils.getNodeType(fieldDeclaration) != ThreadFactory.class) {\n                return addViolationAndReturn(node, data);\n            }\n            return super.visit(node, data);\n        }\n\n        //in newThread(Runnable) method is ok\n        if (isInNewThreadMethod(node)) {\n            return super.visit(node, data);\n        }\n        //implements of ThreadFactory\n        boolean isThreadFactory = (checkForNamingClass(node) || threadFactoryVariable(node))\n            && isInPrimaryOrProtectedMethod(node);\n        if (isThreadFactory) {\n            return super.visit(node, data);\n        }\n        return addViolationAndReturn(node, data);\n    }\n\n    private boolean isAddShutdownHook(ASTAllocationExpression node) {\n        ASTBlockStatement blockStatement = node.getFirstParentOfType(ASTBlockStatement.class);\n        if (blockStatement == null) {\n            return false;\n        }\n        Token token = (Token)blockStatement.jjtGetFirstToken();\n        return Runtime.class.getSimpleName().equals(token.image);\n    }\n\n    private boolean isInStaticInitializer(ASTAllocationExpression node) {\n        ASTInitializer initializer = node.getFirstParentOfType(ASTInitializer.class);\n        return initializer != null && initializer.isStatic();\n    }\n\n    private boolean threadFactoryVariable(ASTAllocationExpression node) {\n        ASTMethodDeclaration methodDeclaration = node.getFirstParentOfType(ASTMethodDeclaration.class);\n        if (methodDeclaration == null) {\n            return false;\n        }\n        ASTVariableDeclarator variableDeclarator = methodDeclaration.getFirstParentOfType(ASTVariableDeclarator.class);\n        return variableDeclarator != null && variableDeclarator.getType() == ThreadFactory.class;\n    }\n\n    private boolean isInNewThreadMethod(ASTAllocationExpression node) {\n        ASTMethodDeclaration methodDeclaration = node.getFirstParentOfType(ASTMethodDeclaration.class);\n        if (methodDeclaration == null) {\n            return false;\n        }\n        if (!returnThread(methodDeclaration)) {\n            return false;\n        }\n        if (!METHOD_NEW_THREAD.equals(methodDeclaration.getMethodName())) {\n            return false;\n        }\n        List<ASTFormalParameter> parameters = methodDeclaration.getFirstDescendantOfType(ASTFormalParameters.class)\n            .findChildrenOfType(ASTFormalParameter.class);\n        return parameters.size() == 1\n            && parameters.get(0).getFirstChildOfType(ASTType.class).getType() == Runnable.class;\n    }\n\n    private boolean isInPrimaryOrProtectedMethod(ASTAllocationExpression node) {\n        ASTMethodDeclaration methodDeclaration = node.getFirstParentOfType(ASTMethodDeclaration.class);\n        return methodDeclaration != null && returnThread(methodDeclaration) && (methodDeclaration.isPrivate()\n            || methodDeclaration.isProtected());\n    }\n\n    private boolean returnThread(ASTMethodDeclaration methodDeclaration) {\n        ASTResultType resultType = methodDeclaration.getFirstChildOfType(ASTResultType.class);\n        ASTType type = resultType.getFirstChildOfType(ASTType.class);\n        return type != null && type.getType() == Thread.class;\n    }\n\n    private Object addViolationAndReturn(ASTAllocationExpression node, Object data) {\n        addViolationWithMessage(data, node, \"java.concurrent.AvoidManuallyCreateThreadRule.violation.msg\");\n        return super.visit(node, data);\n    }\n\n    private boolean checkForNamingClass(ASTAllocationExpression node) {\n        ASTClassOrInterfaceDeclaration classOrInterfaceDeclaration =\n            node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);\n        if (classOrInterfaceDeclaration == null) {\n            return false;\n        }\n        ASTImplementsList implementsList = classOrInterfaceDeclaration.getFirstChildOfType(ASTImplementsList.class);\n        if (implementsList == null) {\n            return false;\n        }\n        List<ASTClassOrInterfaceType> interfaceTypes = implementsList.findChildrenOfType(ASTClassOrInterfaceType.class);\n        for (ASTClassOrInterfaceType type : interfaceTypes) {\n            if (type.getType() == ThreadFactory.class) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/AvoidUseTimerRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport java.util.Timer;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaTypeNode;\n\n/**\n * [Mandatory] Run multiple TimeTask by using ScheduledExecutorService rather than Timer\n * because Timer will kill all running threads in case of failing to catch exception.\n *\n * @author caikang\n * @date 2016/11/15\n */\npublic class AvoidUseTimerRule extends AbstractAliRule {\n    @Override\n    public Object visit(ASTVariableDeclarator node, Object data) {\n        checkType(node, data);\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTPrimaryExpression node, Object data) {\n        ASTVariableDeclarator variableDeclarator = node.getFirstParentOfType(ASTVariableDeclarator.class);\n        if (variableDeclarator != null && variableDeclarator.getType() == Timer.class) {\n            return super.visit(node, data);\n        }\n        checkType(node, data);\n        return super.visit(node, data);\n    }\n\n    private void checkType(AbstractJavaTypeNode node, Object data) {\n        if (node.getType() == Timer.class) {\n            addViolationWithMessage(data, node,\"java.concurrent.AvoidUseTimerRule.violation.msg\");\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/CountDownShouldInFinallyRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTTryStatement;\nimport org.jaxen.JaxenException;\n\n/**\n * [Recommended] When using CountDownLatch to convert asynchronous operations to synchronous ones,\n * each thread must call countdown method before quitting.\n * Make sure to catch any exception during thread running, to let countdown method be executed.\n * If main thread cannot reach await method, program will return until timeout.\n *\n * Note: Be careful, exception thrown by sub-thread cannot be caught by main thread.\n *\n * @author caikang\n * @date 2017/03/29\n */\npublic class CountDownShouldInFinallyRule extends AbstractAliRule {\n    private static final String XPATH = \"./Block/BlockStatement/Statement/StatementExpression\"\n        + \"/PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image,'.countDown')]\";\n\n    @Override\n    public Object visit(ASTTryStatement node, Object data) {\n        try {\n            List<Node> nodes = node.findChildNodesWithXPath(XPATH);\n            if (nodes == null || nodes.isEmpty()) {\n                return super.visit(node, data);\n            }\n            for (Node nameNode : nodes) {\n                if (!(nameNode instanceof ASTName)) {\n                    continue;\n                }\n                ASTName name = (ASTName)nameNode;\n                if (name.getType() != CountDownLatch.class) {\n                    continue;\n                }\n                addViolationWithMessage(data, name, \"java.concurrent.CountDownShouldInFinallyRule.violation.msg\",\n                    new Object[] {name.getImage()});\n            }\n        } catch (JaxenException ignore) {\n        }\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/ThreadLocalShouldRemoveRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.VariableUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Customized ThreadLocal variables must be recycled, especially when using thread pools in which threads\n * are often reused. Otherwise, it may affect subsequent business logic and cause unexpected problems such as memory\n * leak.\n *\n * @author caikang\n * @date 2017/03/29\n */\npublic class ThreadLocalShouldRemoveRule extends AbstractAliRule {\n    private static final String XPATH_TPL = \"//StatementExpression/PrimaryExpression\"\n        + \"/PrimaryPrefix/Name[@Image='%s.remove']\";\n\n    private static final String METHOD_INITIAL_VALUE = \"initialValue\";\n\n    private static final String WITH_INITIAL = \"ThreadLocal.withInitial\";\n\n    @Override\n    public Object visit(ASTCompilationUnit node, Object data) {\n        List<ASTFieldDeclaration> fieldDeclarations = node.findDescendantsOfType(ASTFieldDeclaration.class);\n        if (fieldDeclarations == null || fieldDeclarations.isEmpty()) {\n            return super.visit(node, data);\n        }\n        for (ASTFieldDeclaration fieldDeclaration : fieldDeclarations) {\n            if (NodeUtils.getNodeType(fieldDeclaration) == ThreadLocal.class) {\n                if (checkThreadLocalWithInitalValue(fieldDeclaration)) { continue; }\n                checkThreadLocal(fieldDeclaration, node, data);\n            }\n        }\n        return super.visit(node, data);\n    }\n\n    private boolean checkThreadLocalWithInitalValue(ASTFieldDeclaration fieldDeclaration) {\n        ASTVariableDeclarator variableDeclarator = fieldDeclaration.getFirstDescendantOfType(\n            ASTVariableDeclarator.class);\n        if (variableDeclarator == null) {\n            return false;\n        }\n        // ASTClassOrInterfaceBodyDeclaration.isFindBoundary=true，使用getFirstDescendantOfType不能继续向方法内部查询\n        List<ASTMethodDeclarator> astMethodDeclaratorList = variableDeclarator.findDescendantsOfType(\n            ASTMethodDeclarator.class, true);\n        if (!astMethodDeclaratorList.isEmpty()) {\n            return METHOD_INITIAL_VALUE.equals(astMethodDeclaratorList.get(0).getImage());\n        }\n        ASTName name = variableDeclarator.getFirstDescendantOfType(ASTName.class);\n        return name != null && WITH_INITIAL.equals(name.getImage());\n    }\n\n    private void checkThreadLocal(ASTFieldDeclaration fieldDeclaration, ASTCompilationUnit node, Object data) {\n        try {\n            String variableName = VariableUtils.getVariableName(fieldDeclaration);\n            List<Node> nodes = node.findChildNodesWithXPath(String.format(XPATH_TPL,\n                variableName));\n            if (nodes == null || nodes.isEmpty()) {\n                ViolationUtils.addViolationWithPrecisePosition(this, fieldDeclaration, data,\n                    I18nResources.getMessage(\"java.concurrent.ThreadLocalShouldRemoveRule.violation.msg\",\n                        variableName));\n            }\n        } catch (JaxenException ignore) {\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/ThreadPoolCreationRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.Token;\n\n/**\n * [Mandatory] A thread pool should be created by ThreadPoolExecutor rather than Executors.\n * These would make the parameters of the thread pool understandable.\n * It would also reduce the risk of running out of system resource.\n *\n * @author caikang\n * @date 2016/11/14\n */\npublic class ThreadPoolCreationRule extends AbstractAliRule {\n\n    private static final String DOT = \".\";\n    private static final String COLON = \";\";\n    private static final String NEW = \"new\";\n    private static final String EXECUTORS_NEW = Executors.class.getSimpleName() + DOT + NEW;\n    private static final String FULL_EXECUTORS_NEW = Executors.class.getName() + DOT + NEW;\n    private static final String BRACKETS = \"()\";\n    private static final String NEW_SCHEDULED = \"newScheduledThreadPool\";\n    private static final String NEW_SINGLE_SCHEDULED = \"newSingleThreadScheduledExecutor\";\n\n    @Override\n    public Object visit(ASTCompilationUnit node, Object data) {\n        Object superResult = super.visit(node, data);\n        Info info = new Info();\n\n        List<ASTImportDeclaration> importDeclarations = node.findChildrenOfType(ASTImportDeclaration.class);\n        for (ASTImportDeclaration importDeclaration : importDeclarations) {\n            ASTName name = importDeclaration.getFirstChildOfType(ASTName.class);\n            info.executorsUsed = info.executorsUsed\n                || (name.getType() == Executors.class || Executors.class.getName().equals(name.getImage()));\n            if (name.getImage().startsWith(Executors.class.getName() + DOT)) {\n                info.importedExecutorsMethods.add(name.getImage());\n            }\n        }\n        List<ASTPrimaryExpression> primaryExpressions = node.findDescendantsOfType(ASTPrimaryExpression.class);\n        for(ASTPrimaryExpression primaryExpression : primaryExpressions){\n            if (!info.executorsUsed && info.importedExecutorsMethods.isEmpty()) {\n                continue;\n            }\n\n            Token initToken = (Token)primaryExpression.jjtGetFirstToken();\n            if (!checkInitStatement(initToken, info)) {\n                addViolationWithMessage(data, primaryExpression,\"java.concurrent.ThreadPoolCreationRule.violation.msg\");\n            }\n        }\n        return superResult;\n    }\n\n    private boolean checkInitStatement(Token token, Info info) {\n        String fullAssignStatement = getFullAssignStatement(token);\n        // do not check newScheduledThreadPool and newSingleThreadScheduledExecutor\n        if (NEW_SCHEDULED.equals(fullAssignStatement) || NEW_SINGLE_SCHEDULED.equals(fullAssignStatement)) {\n            return true;\n        }\n        if (fullAssignStatement.startsWith(EXECUTORS_NEW)) {\n            return false;\n        }\n        if (!fullAssignStatement.startsWith(NEW) && !fullAssignStatement.startsWith(FULL_EXECUTORS_NEW)) {\n            return true;\n        }\n        // code with lambda\n        int index = fullAssignStatement.indexOf(BRACKETS);\n        if (index == -1) {\n            return true;\n        }\n        fullAssignStatement = fullAssignStatement.substring(0, index);\n        // java.util.concurrent.Executors.newxxxx\n        if (info.importedExecutorsMethods.contains(fullAssignStatement)) {\n            return false;\n        }\n        // static import\n        return !info.importedExecutorsMethods.contains(Executors.class.getName() + DOT + fullAssignStatement);\n    }\n\n    private String getFullAssignStatement(final Token token) {\n        if (token == null) {\n            return \"\";\n        }\n        StringBuilder sb = new StringBuilder(48);\n        Token next = token;\n        while (next.next != null && !COLON.equals(next.image)) {\n            sb.append(next.image);\n            next = next.next;\n        }\n        return sb.toString();\n    }\n\n    class Info {\n        boolean executorsUsed;\n        Set<String> importedExecutorsMethods = new HashSet<>();\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/ThreadShouldSetNameRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTArgumentList;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;\nimport net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;\nimport net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\n\n/**\n * [Mandatory] A meaningful thread name is helpful to trace the error information,\n * so assign a name when creating threads or thread pools.\n *\n * Detection rule\n * 1. Use specific constructor while create thread pool\n * 2. Use Executors.defaultThreadFactory() is not allowed\n *\n * @author caikang\n * @date 2016/11/16\n * @see AvoidManuallyCreateThreadRule\n */\npublic class ThreadShouldSetNameRule extends AbstractAliRule {\n    private static final int ARGUMENT_LENGTH_2 = 2;\n    private static final int ARGUMENT_LENGTH_6 = 6;\n    private static final int INDEX_1 = 1;\n    private static final int SINGLE_LENGTH = 1;\n\n    private static final String MESSAGE_KEY_PREFIX = \"java.concurrent.ThreadShouldSetNameRule.violation.msg\";\n\n    @Override\n    public Object visit(ASTAllocationExpression node, Object data) {\n        //Custom Class\n        if (node.getType() == null) {\n            return super.visit(node, data);\n        }\n        if (!ExecutorService.class.isAssignableFrom(node.getType())) {\n            return super.visit(node, data);\n        }\n        if (ThreadPoolExecutor.class == node.getType()) {\n            return checkThreadPoolExecutor(node, data);\n        }\n        if (ScheduledThreadPoolExecutor.class == node.getType()) {\n            return checkSchedulePoolExecutor(node, data);\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        return super.visit(node, data);\n    }\n\n    private Object checkThreadPoolExecutor(ASTAllocationExpression node, Object data) {\n        ASTArgumentList argumentList = node.getFirstDescendantOfType(ASTArgumentList.class);\n        if (argumentList.jjtGetNumChildren() > ARGUMENT_LENGTH_6) {\n            return true;\n        }\n        if (argumentList.jjtGetNumChildren() < ARGUMENT_LENGTH_6\n            || !checkThreadFactoryArgument((ASTExpression)argumentList.jjtGetChild(ARGUMENT_LENGTH_6 - INDEX_1))) {\n            addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + \".ThreadPoolExecutor\");\n        }\n        return super.visit(node, data);\n    }\n\n    private Object checkSchedulePoolExecutor(ASTAllocationExpression node, Object data) {\n        ASTArgumentList argumentList = node.getFirstDescendantOfType(ASTArgumentList.class);\n        if (argumentList.jjtGetNumChildren() > ARGUMENT_LENGTH_2) {\n            return true;\n        }\n        if (argumentList.jjtGetNumChildren() < ARGUMENT_LENGTH_2\n            || !checkThreadFactoryArgument((ASTExpression)argumentList.jjtGetChild(ARGUMENT_LENGTH_2 - INDEX_1))) {\n            addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + \".ScheduledThreadPoolExecutor\");\n        }\n        return super.visit(node, data);\n    }\n\n    private boolean checkThreadFactoryArgument(ASTExpression expression) {\n        if (expression.getType() != null && ThreadFactory.class.isAssignableFrom(expression.getType())) {\n            return true;\n        }\n        ASTName name = expression.getFirstDescendantOfType(ASTName.class);\n        if (name != null && name.getType() == Executors.class) {\n            return false;\n        }\n        ASTLambdaExpression lambdaExpression = expression.getFirstDescendantOfType(ASTLambdaExpression.class);\n        if (lambdaExpression != null) {\n            return isThreadFactoryLambda(lambdaExpression);\n        } else if (expression.getType() != null\n            && RejectedExecutionHandler.class.isAssignableFrom(expression.getType())) {\n            return false;\n        }\n        return true;\n    }\n\n    private boolean isThreadFactoryLambda(ASTLambdaExpression lambdaExpression) {\n        List<ASTVariableDeclaratorId> variableDeclaratorIds =\n            lambdaExpression.findChildrenOfType(ASTVariableDeclaratorId.class);\n        if (variableDeclaratorIds != null && !variableDeclaratorIds.isEmpty()) {\n            return variableDeclaratorIds.size() == SINGLE_LENGTH;\n        }\n\n        // like (Runnable r) ->\n        ASTFormalParameters parameters = lambdaExpression.getFirstChildOfType(ASTFormalParameters.class);\n        if (parameters == null) {\n            return false;\n        }\n\n        ASTFormalParameter parameter = parameters.getFirstChildOfType(ASTFormalParameter.class);\n        if (parameter == null) {\n            return false;\n        }\n        ASTVariableDeclaratorId variableDeclaratorId = parameter.getFirstChildOfType(ASTVariableDeclaratorId.class);\n        if (variableDeclaratorId == null) {\n            return false;\n        }\n        return Runnable.class == variableDeclaratorId.getType();\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/constant/UndefineMagicConstantRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.constant;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.namelist.NameListConfig;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTForStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTIfStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTLiteral;\nimport net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;\nimport net.sourceforge.pmd.util.StringUtil;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Magic values, except for predefined, are forbidden in coding.\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n */\npublic class UndefineMagicConstantRule extends AbstractAliRule {\n\n    /**\n     * white list for undefined variable, may be added\n     */\n    private final static List<String> LITERAL_WHITE_LIST = NameListConfig.NAME_LIST_SERVICE.getNameList(\n        UndefineMagicConstantRule.class.getSimpleName(), \"LITERAL_WHITE_LIST\");\n\n    private final static String XPATH = \"//Literal/../../../../..[not(VariableInitializer)]\";\n\n    /**\n     * An undefined that belongs to non-looped if statements\n     *\n     * @param node compilation unit\n     * @param data rule context\n     */\n    @Override\n    public Object visit(ASTCompilationUnit node, Object data) {\n        // removed repeat magic value , to prevent the parent class to find sub-variable nodes when there is a repeat\n        List<ASTLiteral> currentLiterals = new ArrayList<ASTLiteral>();\n        try {\n            // Find the parent node of the undefined variable\n            List<Node> parentNodes = node.findChildNodesWithXPath(XPATH);\n\n            for (Node parentItem : parentNodes) {\n                List<ASTLiteral> literals = parentItem.findDescendantsOfType(ASTLiteral.class);\n                for (ASTLiteral literal : literals) {\n                    if (inBlackList(literal) && !currentLiterals.contains(literal)) {\n                        currentLiterals.add(literal);\n                        String imageReplace = StringUtils.replace(literal.getImage(), \"{\", \"'{\");\n                        addViolationWithMessage(data, literal,\n                            \"java.constant.UndefineMagicConstantRule.violation.msg\", new Object[] {imageReplace});\n                    }\n                }\n            }\n        } catch (JaxenException e) {\n            e.printStackTrace();\n        }\n        return super.visit(node, data);\n    }\n\n    /**\n     * Undefined variables are in the blacklist\n     *\n     * @param literal\n     * @return\n     */\n    private boolean inBlackList(ASTLiteral literal) {\n        String name = literal.getImage();\n        int lineNum = literal.getBeginLine();\n        // name is null,bool literal，belongs to white list\n        if (name == null) {\n            return false;\n        }\n        // filter white list\n        for (String whiteItem : LITERAL_WHITE_LIST) {\n            if (whiteItem.equals(name)) {\n                return false;\n            }\n        }\n        ASTIfStatement ifStatement = literal.getFirstParentOfType(ASTIfStatement.class);\n        if (ifStatement != null && lineNum == ifStatement.getBeginLine()) {\n            ASTForStatement forStatement = ifStatement.getFirstParentOfType(ASTForStatement.class);\n            ASTWhileStatement whileStatement = ifStatement.getFirstParentOfType(ASTWhileStatement.class);\n            return forStatement == null && whileStatement == null;\n        }\n\n        // judge magic value belongs to  for statement \n        ASTForStatement blackForStatement = literal.getFirstParentOfType(ASTForStatement.class);\n        if (blackForStatement != null && lineNum == blackForStatement.getBeginLine()) {\n            return true;\n        }\n\n        // judge magic value belongs to while statement\n        ASTWhileStatement blackWhileStatement = literal.getFirstParentOfType(ASTWhileStatement.class);\n        return blackWhileStatement != null && lineNum == blackWhileStatement.getBeginLine();\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/constant/UpperEllRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.constant;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTLiteral;\n\n/**\n * [Mandatory] 'L' instead of 'l' should be used for long or Long variable because 'l' is easily to\n * be regarded as number 1 in mistake.\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n */\npublic class UpperEllRule extends AbstractAliRule {\n    private static final String LOWERCASE_L = \"l\";\n\n    @Override\n    public Object visit(ASTLiteral node, Object data) {\n        String image = node.getImage();\n        // if it is an integer and ends with l, collects the current violation code\n        if (image != null && node.isLongLiteral() && image.endsWith(LOWERCASE_L)) {\n            addViolationWithMessage(data, node, \"java.constant.UpperEllRule.violation.msg\",\n                new Object[] {node.getImage()});\n        }\n        return super.visit(node, data);\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/exception/AvoidReturnInFinallyRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.exception;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * [Mandatory] Never use return within a finally block.\n * A return statement in a finally block will cause exception or result\n * in a discarded return value in the try-catch block.\n * \n * @author zenghou.fw\n * @date 2017/03/29\n */\npublic class AvoidReturnInFinallyRule extends AbstractXpathRule {\n    private static final String XPATH = \"//FinallyStatement//ReturnStatement\";\n\n    public AvoidReturnInFinallyRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            I18nResources.getMessage(\"java.exception.AvoidReturnInFinallyRule.violation.msg\"));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/exception/MethodReturnWrapperTypeRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.exception;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.namelist.NameListConfig;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\nimport org.jaxen.JaxenException;\n\n/**\n * [Recommended] If the return type is primitive, return a value of wrapper class may cause NullPointerException.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class MethodReturnWrapperTypeRule extends AbstractAliRule {\n    private static final Map<String, String> PRIMITIVE_TYPE_TO_WAPPER_TYPE = NameListConfig.NAME_LIST_SERVICE\n        .getNameMap(\"MethodReturnWrapperTypeRule\", \"PRIMITIVE_TYPE_TO_WAPPER_TYPE\", String.class, String.class);\n    private static final String METHOD_RETURN_TYPE_XPATH = \"ResultType/Type/PrimitiveType\";\n    private static final String METHOD_RETURN_OBJECT_XPATH\n        = \"Block/BlockStatement/Statement/ReturnStatement/Expression/PrimaryExpression/PrimaryPrefix/Name\";\n    private static final String METHOD_VARIABLE_TYPE_XPATH = \"Type/ReferenceType/ClassOrInterfaceType\";\n    private static final String METHOD_VARIABLE_NAME_XPATH\n        = \"Block/BlockStatement/LocalVariableDeclaration/VariableDeclarator/VariableDeclaratorId\";\n\n    @Override\n    public Object visit(ASTMethodDeclaration node, Object data) {\n        try {\n            List<Node> astPrimitiveTypeList = node.findChildNodesWithXPath(METHOD_RETURN_TYPE_XPATH);\n            //check the method return type\n            if (!(astPrimitiveTypeList != null && astPrimitiveTypeList.size() == 1)) {\n                return super.visit(node, data);\n            }\n            ASTPrimitiveType astPrimitiveType = (ASTPrimitiveType)astPrimitiveTypeList.get(0);\n            //If the return type is not a basic types,skip\n            if (!(astPrimitiveType.getType() != null && astPrimitiveType.getType().isPrimitive())) {\n                return super.visit(node, data);\n            }\n            //the return type\n            String primitiveTypeName = astPrimitiveType.getType().getName();\n            //the return node\n            List<Node> nameList = node.findChildNodesWithXPath(METHOD_RETURN_OBJECT_XPATH);\n            if (nameList == null || nameList.size() != 1) {\n                return super.visit(node, data);\n            }\n            //if the local variable is empty,skip\n            List<Node> methodVariableNameList = node.findChildNodesWithXPath(METHOD_VARIABLE_NAME_XPATH);\n            if (methodVariableNameList == null || methodVariableNameList.size() == 0) {\n                return super.visit(node, data);\n            }\n            ASTName astName = (ASTName)nameList.get(0);\n            String variableName = astName.getImage();\n            //iterate all the method of variable nodes\n            for (Node methodVariableNameNode : methodVariableNameList) {\n                ASTVariableDeclaratorId astVariableDeclaratorId\n                    = (ASTVariableDeclaratorId)methodVariableNameNode;\n                //find out the variable named the same with return node\n                if (!variableName.equals(astVariableDeclaratorId.getImage())) {\n                    continue;\n                }\n                ASTLocalVariableDeclaration astLocalVariableDeclaration = astVariableDeclaratorId\n                    .getFirstParentOfType(ASTLocalVariableDeclaration.class);\n                //check local variables type\n                List<Node> nodeList = astLocalVariableDeclaration.findChildNodesWithXPath(\n                    METHOD_VARIABLE_TYPE_XPATH);\n\n                if (nodeList != null && nodeList.size() == 1) {\n                    ASTClassOrInterfaceType astClassOrInterfaceType = (ASTClassOrInterfaceType)nodeList.get(\n                        0);\n                    //if variable type is a value of wrapper\n                    if (PRIMITIVE_TYPE_TO_WAPPER_TYPE.get(primitiveTypeName) != null\n                        && PRIMITIVE_TYPE_TO_WAPPER_TYPE.get(primitiveTypeName).equals(\n                        astClassOrInterfaceType.getType().getSimpleName())) {\n                        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                            I18nResources.getMessage(\"java.exception.MethodReturnWrapperTypeRule.violation.msg\",\n                                primitiveTypeName, astClassOrInterfaceType.getType().getSimpleName()));\n                    }\n                }\n            }\n        } catch (JaxenException e) {\n            return super.visit(node, data);\n        }\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/exception/TransactionMustHaveRollbackRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.exception;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTAnnotation;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Make sure to invoke the rollback if a method throws an Exception.\n *\n * @author caikang\n * @date 2017/03/29\n */\npublic class TransactionMustHaveRollbackRule extends AbstractAliRule {\n    private static final String TRANSACTIONAL_ANNOTATION_NAME = \"Transactional\";\n    private static final String TRANSACTIONAL_FULL_NAME = \"org.springframework.transaction.annotation.\"\n        + TRANSACTIONAL_ANNOTATION_NAME;\n    private static final String ROLLBACK_PREFIX = \"rollback\";\n\n    private static final String READ_ONLY = \"readOnly\";\n\n    private static final String PROPAGATION_NOT_SUPPORTED = \"Propagation.NOT_SUPPORTED\";\n\n    private static final String XPATH_FOR_ROLLBACK = \"//StatementExpression/PrimaryExpression\"\n        + \"/PrimaryPrefix/Name[ends-with(@Image,'rollback')]\";\n\n    private static final String MESSAGE_KEY_PREFIX = \"java.exception.TransactionMustHaveRollbackRule.violation.msg\";\n\n    @Override\n    public Object visit(ASTAnnotation node, Object data) {\n        ASTName name = node.getFirstDescendantOfType(ASTName.class);\n        boolean noTransactional = name == null || !(TRANSACTIONAL_ANNOTATION_NAME.equals(name.getImage())\n            && !TRANSACTIONAL_FULL_NAME.equals(name.getImage()));\n        if (noTransactional) {\n            return super.visit(node, data);\n        }\n        List<ASTMemberValuePair> memberValuePairList = node.findDescendantsOfType(ASTMemberValuePair.class);\n        if (shouldSkip(memberValuePairList)) {\n            return super.visit(node, data);\n        }\n\n        ASTClassOrInterfaceDeclaration classOrInterfaceDeclaration\n            = getSiblingForType(node, ASTClassOrInterfaceDeclaration.class);\n        if (classOrInterfaceDeclaration != null) {\n            addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + \".simple\");\n            return super.visit(node, data);\n        }\n\n        ASTMethodDeclaration methodDeclaration = getSiblingForType(node, ASTMethodDeclaration.class);\n        if (methodDeclaration == null) {\n            return super.visit(node, data);\n        }\n        try {\n            List<Node> nodes = methodDeclaration.findChildNodesWithXPath(XPATH_FOR_ROLLBACK);\n            if (nodes != null && !nodes.isEmpty()) {\n                return super.visit(node, data);\n            }\n            addViolationWithMessage(data, methodDeclaration, MESSAGE_KEY_PREFIX,\n                new Object[] {methodDeclaration.getMethodName()});\n        } catch (JaxenException ignore) {\n        }\n        return super.visit(node, data);\n    }\n\n    private boolean shouldSkip(List<ASTMemberValuePair> memberValuePairList) {\n        for (ASTMemberValuePair pair : memberValuePairList) {\n            String image = pair.getImage();\n            if (image == null) {\n                continue;\n            }\n            if (image.startsWith(ROLLBACK_PREFIX) || image.startsWith(READ_ONLY)) {\n                return true;\n            }\n            ASTName name = pair.getFirstDescendantOfType(ASTName.class);\n            if (name != null && PROPAGATION_NOT_SUPPORTED.equals(name.getImage())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * annotation is sibling of classOrInterface declaration or method declaration\n     *\n     * @param node transactional annotation\n     * @param clz  classOrInterface declaration or method declaration\n     * @param <T>  generic\n     * @return sibling node\n     */\n    private <T> T getSiblingForType(ASTAnnotation node, Class<T> clz) {\n        Node parent = node.jjtGetParent();\n        int num = parent.jjtGetNumChildren();\n        for (int i = 0; i < num; i++) {\n            Node child = parent.jjtGetChild(i);\n            if (clz.isAssignableFrom(child.getClass())) {\n                return clz.cast(child);\n            }\n            if (!(child instanceof ASTAnnotation)) {\n                return null;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/AvoidComplexConditionRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.flowcontrol;\n\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * [Mandatory] Do not use complicated statements in conditional statements (except for frequently used methods\n * like getXxx/isXxx). Use boolean variables to store results of complicated statements temporarily will increase\n * the code's readability.\n *\n * @author zenghou.fw\n * @date 2017/04/11\n */\npublic class AvoidComplexConditionRule extends AbstractXpathRule {\n    private static final String XPATH = \"(//IfStatement/Expression\"\n        + \"|//ConditionalExpression[@Ternary = 'true']/PrimaryExpression)\"\n        + \"[count(.//ConditionalAndExpression) + count(.//ConditionalOrExpression) > 1]\";\n\n    public AvoidComplexConditionRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            \"java.flowcontrol.AvoidComplexConditionRule.violation.msg\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/AvoidNegationOperatorRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.flowcontrol;\n\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * [Recommended] Avoid using the negation operator '!'.\n * Note: The negation operator is not easy to be quickly understood. There must be a positive\n * way to represent the same logic.\n *\n * @author zenghou.fw\n * @date 2017/11/21\n */\npublic class AvoidNegationOperatorRule extends AbstractXpathRule {\n    private static final String XPATH = \"//UnaryExpressionNotPlusMinus[child::PrimaryExpression\"\n        + \"//PrimaryPrefix/Expression/RelationalExpression]\"\n        + \"|//UnaryExpressionNotPlusMinus[child::PrimaryExpression\"\n        + \"//PrimaryPrefix/Expression/EqualityExpression]\";\n\n    public AvoidNegationOperatorRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            \"java.flowcontrol.AvoidNegationOperatorRule.violation.msg\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/NeedBraceRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.flowcontrol;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTBlock;\nimport net.sourceforge.pmd.lang.java.ast.ASTForStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTIfStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;\n\n/**\n * [Mandatory] Braces are used with if, else, for, do and while statements, even if the body contains only a single\n * statement. Avoid using the following example:\n * <pre>\n * if (condition) statements;\n * </pre>\n *\n * @author zenghou.fw\n * @date 2016/11/22\n */\npublic class NeedBraceRule extends AbstractAliRule {\n    private static final String STATEMENT_BLOCK = \"Statement/Block\";\n\n    private static final String MESSAGE_KEY = \"java.flowcontrol.NeedBraceRule.violation.msg\";\n\n    @Override\n    public Object visit(ASTIfStatement node, Object data) {\n        // SwitchStatement without {} fail by compilaton, no need to check here\n        if (!node.hasDescendantMatchingXPath(STATEMENT_BLOCK)) {\n            addViolationWithMessage(data, node, MESSAGE_KEY,\n                new Object[] {node.jjtGetFirstToken().toString()});\n        }\n        if (node.hasElse()) {\n            // IfStatement with else have 2 expression blocks, should never throws NPE\n            ASTStatement elseStms = node.findChildrenOfType(ASTStatement.class).get(1);\n\n            if (!elseStms.hasDescendantOfAnyType(ASTBlock.class, ASTIfStatement.class)) {\n                addViolationWithMessage(data, elseStms, MESSAGE_KEY, new Object[] {\"else\"});\n            }\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTForStatement node, Object data) {\n        if (!node.hasDescendantMatchingXPath(STATEMENT_BLOCK)) {\n            addViolationWithMessage(data, node, MESSAGE_KEY, new Object[] {\"for\"});\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTWhileStatement node, Object data) {\n        if (!node.hasDescendantMatchingXPath(STATEMENT_BLOCK)) {\n            addViolationWithMessage(data, node, MESSAGE_KEY, new Object[] {\"while\"});\n        }\n        return super.visit(node, data);\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/SwitchStatementRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.flowcontrol;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;\n\n/**\n * [Mandatory] In a switch block, each case should be finished by break/return.\n * If not, a note should be included to describe at which case it will stop. Within every switch block,\n * a default statement must be present, even if it is empty.\n *\n * @author zenghou.fw\n * @date 2016/11/17\n */\npublic class SwitchStatementRule extends AbstractAliRule {\n    private static final String MESSAGE_KEY_PREFIX = \"java.flowcontrol.SwitchStatementRule.violation\";\n\n    @Override\n    public Object visit(ASTSwitchStatement node, Object data) {\n        checkDefault(node, data);\n\n        checkFallThrough(node, data);\n\n        return super.visit(node, data);\n    }\n\n    /**\n     * Check if switch statement contains default branch\n     *\n     * @param node\n     * @param data\n     */\n    private void checkDefault(ASTSwitchStatement node, Object data) {\n        final String switchCheckXpath = \"SwitchLabel[@Default = 'true']\";\n        if (!node.hasDescendantMatchingXPath(switchCheckXpath)) {\n            addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + \".nodefault\");\n        }\n    }\n\n    /**\n     * Check the availability of break, return, throw, continue in case statement\n     *\n     * @param node\n     * @param data\n     */\n    private void checkFallThrough(ASTSwitchStatement node, Object data) {\n        // refer the rule MissingBreakInSwitch of PMD\n        final String xpath = \"../SwitchStatement[(count(.//BreakStatement)\"\n            + \" + count(BlockStatement//Statement/ReturnStatement)\"\n            + \" + count(BlockStatement//Statement/ContinueStatement)\"\n            + \" + count(BlockStatement//Statement/ThrowStatement)\"\n            + \" + count(BlockStatement//Statement/IfStatement[@Else='true'\"\n            + \" and Statement[2][ReturnStatement|ContinueStatement|ThrowStatement]]\"\n            + \"/Statement[1][ReturnStatement|ContinueStatement|ThrowStatement])\"\n            + \" + count(SwitchLabel[name(following-sibling::node()) = 'SwitchLabel'])\"\n            + \" + count(SwitchLabel[count(following-sibling::node()) = 0])\"\n            + \"  < count (SwitchLabel[@Default != 'true'])\"\n            + \" + count(SwitchLabel[@Default = 'true']/following-sibling::BlockStatement//Statement/ReturnStatement)\"\n            + \" + count(SwitchLabel[@Default = 'true']/following-sibling::BlockStatement//Statement/ContinueStatement)\"\n            + \" + count(SwitchLabel[@Default = 'true']/following-sibling::BlockStatement//Statement/ThrowStatement)\"\n            + \")]\";\n\n        if (node.hasDescendantMatchingXPath(xpath)) {\n            addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + \".notermination\");\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/AbstractClassShouldStartWithAbstractNamingRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\n\n/**\n * [Mandatory] Abstract class names must start with Abstract or Base.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class AbstractClassShouldStartWithAbstractNamingRule extends AbstractXpathRule {\n    private static final String XPATH = \"//ClassOrInterfaceDeclaration\"\n        + \" [@Abstract='true' and @Interface='false'][not (matches(@Image,'^(Abstract|Base).*'))]\";\n\n    public AbstractClassShouldStartWithAbstractNamingRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        if (node instanceof ASTClassOrInterfaceDeclaration) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                I18nResources.getMessage(\"java.naming.AbstractClassShouldStartWithAbstractNamingRule.violation.msg\",\n                    node.getImage()));\n        } else {\n            super.addViolation(data, node, arg);\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/ArrayNamingShouldHaveBracketRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * [Mandatory] Brackets are a part of an Array type. The definition could be: String[] args;\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class ArrayNamingShouldHaveBracketRule extends AbstractXpathRule {\n    private static final String XPATH = \"//VariableDeclaratorId[../..[@Array = 'true']]\"\n        + \"[../../Type/ReferenceType[@Array != 'true']]\";\n\n    public ArrayNamingShouldHaveBracketRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            I18nResources.getMessage(\"java.naming.ArrayNamingShouldHaveBracketRule.violation.msg\",\n                node.getImage()));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/AvoidStartWithDollarAndUnderLineNamingRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\n\n/**\n * [Mandatory] All names should not start or end with an underline or a dollar sign.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class AvoidStartWithDollarAndUnderLineNamingRule extends AbstractAliRule {\n    private static final String DOLLAR = \"$\";\n    private static final String UNDERSCORE = \"_\";\n    private static final String FORMAT = I18nResources.getMessage(\n        \"java.naming.AvoidStartWithDollarAndUnderLineNamingRule.violation.msg\");\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (node.getImage().startsWith(DOLLAR) || node.getImage().startsWith(UNDERSCORE)) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data, String.format(FORMAT, node.getImage()));\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTVariableDeclaratorId node, Object data) {\n        if (node.getImage().startsWith(DOLLAR) || node.getImage().startsWith(UNDERSCORE)) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data, String.format(FORMAT, node.getImage()));\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTMethodDeclarator node, Object data) {\n        if (node.getImage().startsWith(DOLLAR) || node.getImage().startsWith(UNDERSCORE)) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data, String.format(FORMAT, node.getImage()));\n        }\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/BooleanPropertyShouldNotStartWithIsRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\n\n/**\n * [Mandatory] Do not add 'is' as prefix while defining Boolean variable, since it may cause a serialization exception\n * in some Java Frameworks.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class BooleanPropertyShouldNotStartWithIsRule extends AbstractXpathRule {\n    private static final String XPATH = \"//VariableDeclaratorId[(ancestor::ClassOrInterfaceDeclaration)[\"\n        + \"@Interface='false' and ( ends-with(@Image, 'DO') or ends-with(@Image, 'DTO')\"\n        + \" or ends-with(@Image, 'VO') or ends-with(@Image, 'DAO'))]]\"\n        + \"[../../../FieldDeclaration/Type/PrimitiveType[@Image = 'boolean']][.[ starts-with(@Image, 'is')]]\";\n\n    public BooleanPropertyShouldNotStartWithIsRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        if (node instanceof ASTVariableDeclaratorId) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                I18nResources.getMessage(\"java.naming.BooleanPropertyShouldNotStartWithIsRule.violation.msg\",\n                    node.getImage()));\n        } else {\n            super.addViolation(data, node, arg);\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/ClassNamingShouldBeCamelRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.namelist.NameListConfig;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\n\n/**\n * [Mandatory] Class names should be nouns in UpperCamelCase except domain models: DO, BO, DTO, VO, etc.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class ClassNamingShouldBeCamelRule extends AbstractAliRule {\n\n    private static final Pattern PATTERN\n        = Pattern.compile(\"^I?([A-Z][a-z0-9]+)+(([A-Z])|(DO|DTO|VO|DAO|BO|DAOImpl|YunOS|AO|PO))?$\");\n\n    private static final List<String> CLASS_NAMING_WHITE_LIST = NameListConfig.NAME_LIST_SERVICE.getNameList(\n        ClassNamingShouldBeCamelRule.class.getSimpleName(), \"CLASS_NAMING_WHITE_LIST\");\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        for (String s : CLASS_NAMING_WHITE_LIST) {\n            if (node.getImage().contains(s)) {\n                return super.visit(node, data);\n            }\n        }\n        if (PATTERN.matcher(node.getImage()).matches()) {\n            return super.visit(node, data);\n        }\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            I18nResources.getMessage(\"java.naming.ClassNamingShouldBeCamelRule.violation.msg\",\n                node.getImage()));\n\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/ConstantFieldShouldBeUpperCaseRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.namelist.NameListConfig;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * [Mandatory] Constant variable names should be written in upper characters separated by underscores. These names\n * should be semantically complete and clear.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class ConstantFieldShouldBeUpperCaseRule extends AbstractAliRule {\n    private static final String SERVICE_SUFFIX = \"Service\";\n    private static final Set<String> LOG_VARIABLE_TYPE_SET = new HashSet<>(NameListConfig.NAME_LIST_SERVICE.getNameList(\n        \"ConstantFieldShouldBeUpperCaseRule\", \"LOG_VARIABLE_TYPE_SET\"));\n    private static final Set<String> WHITE_LIST = new HashSet<>(NameListConfig.NAME_LIST_SERVICE.getNameList(\n        \"ConstantFieldShouldBeUpperCaseRule\", \"WHITE_LIST\"));\n\n    @Override\n    public Object visit(ASTFieldDeclaration node, Object data) {\n        if (!(node.isStatic() && node.isFinal())) {\n            return super.visit(node, data);\n        }\n        //If the variable is of type Log  or Logger,do not check\n        ASTClassOrInterfaceType classOrInterfaceType = node.getFirstDescendantOfType(ASTClassOrInterfaceType.class);\n        if (classOrInterfaceType != null && LOG_VARIABLE_TYPE_SET.contains(classOrInterfaceType.getImage())) {\n            return super.visit(node, data);\n        }\n        //filter by white list，such as the serialVersionUID\n        String constantName = node.jjtGetChild(1).jjtGetChild(0).getImage();\n        boolean inWhiteList = StringUtils.isEmpty(constantName) || WHITE_LIST.contains(constantName)\n            || constantName.endsWith(SERVICE_SUFFIX);\n        if (inWhiteList) {\n            return super.visit(node, data);\n        }\n        //Constant should be upper\n        if (!(constantName.equals(constantName.toUpperCase()))) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                I18nResources.getMessage(\"java.naming.ConstantFieldShouldBeUpperCaseRule.violation.msg\",\n                    constantName));\n        }\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/ExceptionClassShouldEndWithExceptionRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTExtendsList;\nimport net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * [Mandatory] Exception class names must be ended with Exception.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class ExceptionClassShouldEndWithExceptionRule extends AbstractAliRule {\n\n    private static final String EXCEPTION_END_SUFFIX = \"Exception\";\n\n    @Override\n    public Object visit(ASTExtendsList node, Object data) {\n        ASTClassOrInterfaceType astClassOrInterfaceType = node.getFirstChildOfType(ASTClassOrInterfaceType.class);\n        if ((astClassOrInterfaceType == null) || (!(TypeHelper.isA(astClassOrInterfaceType, Throwable.class)))) {\n            return super.visit(node, data);\n        }\n\n        ASTClassOrInterfaceDeclaration astClassOrInterfaceDeclaration = node.getFirstParentOfType(\n            ASTClassOrInterfaceDeclaration.class);\n        boolean isExceptionViolation = astClassOrInterfaceDeclaration != null\n            && StringUtils.isNotEmpty(astClassOrInterfaceDeclaration.getImage())\n            && !astClassOrInterfaceDeclaration.getImage().endsWith(EXCEPTION_END_SUFFIX);\n        if (isExceptionViolation) {\n            ViolationUtils.addViolationWithPrecisePosition(this, astClassOrInterfaceDeclaration, data,\n                I18nResources.getMessage(\"java.naming.ExceptionClassShouldEndWithExceptionRule.violation.msg\",\n                    astClassOrInterfaceDeclaration.getImage()));\n        }\n        return super.visit(node, data);\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/LowerCamelCaseVariableNamingRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport java.util.regex.Pattern;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.StringAndCharConstants;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\n\n/**\n * [Mandatory] Method names, parameter names, member variable names, and local variable names should be written in\n * lowerCamelCase.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class LowerCamelCaseVariableNamingRule extends AbstractAliRule {\n\n    private static final String MESSAGE_KEY_PREFIX = \"java.naming.LowerCamelCaseVariableNamingRule.violation.msg\";\n    private Pattern pattern = Pattern.compile(\"^[a-z][a-z0-9]*([A-Z][a-z0-9]+)*(DO|DTO|VO|DAO|BO|DOList|DTOList|VOList|DAOList|BOList|X|Y|Z|UDF|UDAF|[A-Z])?$\");\n\n    @Override\n    public Object visit(final ASTVariableDeclaratorId node, Object data) {\n        //避免与 AvoidStartWithDollarAndUnderLineNamingRule 重复判断(例: $myTest)\n        if (variableNamingStartOrEndWithDollarAndUnderLine(node.getImage())) {\n            return super.visit(node, data);\n        }\n        // Constant named does not apply to this rule\n        ASTTypeDeclaration typeDeclaration = node.getFirstParentOfType(ASTTypeDeclaration.class);\n        Node jjtGetChild = typeDeclaration.jjtGetChild(0);\n        if (jjtGetChild instanceof ASTAnnotationTypeDeclaration) {\n            return super.visit(node, data);\n        }\n\n        ASTFieldDeclaration astFieldDeclaration = node.getFirstParentOfType(ASTFieldDeclaration.class);\n        boolean isNotCheck = astFieldDeclaration != null && (astFieldDeclaration.isFinal() || astFieldDeclaration\n            .isStatic());\n        if (isNotCheck) {\n            return super.visit(node, data);\n        }\n\n        // variable naming violate lowerCamelCase\n        if (!(pattern.matcher(node.getImage()).matches())) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".variable\", node.getImage()));\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTMethodDeclarator node, Object data) {\n        if (!variableNamingStartOrEndWithDollarAndUnderLine(node.getImage())) {\n            if (!(pattern.matcher(node.getImage()).matches())) {\n                ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                    I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".method\", node.getImage()));\n            }\n        }\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTAnnotationTypeDeclaration node, Object data) {\n        //对所有注解内的内容不做检查\n        return null;\n    }\n\n    private boolean variableNamingStartOrEndWithDollarAndUnderLine(String variable) {\n        return variable.startsWith(StringAndCharConstants.DOLLAR)\n            || variable.startsWith(StringAndCharConstants.UNDERSCORE);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/PackageNamingRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * [Mandatory] Package should be named in lowercase characters. There should be only one English word after\n * each dot. Package names are always in singular format while class name can be in plural format if necessary.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class PackageNamingRule extends AbstractXpathRule {\n    private static final String XPATH = \"//PackageDeclaration/Name\"\n        + \"[not (matches(@Image, '^[a-z0-9]+(\\\\.[a-z][a-z0-9]*)*$'))]\";\n\n    public PackageNamingRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            I18nResources.getMessage(\"java.naming.PackageNamingRule.violation.msg\", node.getImage()));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/ServiceOrDaoClassShouldEndWithImplRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * [Mandatory] All Service and DAO classes must be interface based on SOA principle. Implementation class names\n * should be ended with Impl.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class ServiceOrDaoClassShouldEndWithImplRule extends AbstractXpathRule {\n    private static final String XPATH = \"//ClassOrInterfaceDeclaration\"\n        + \"[ .[@Interface='false'] and .[@Abstract='false'] and ./ImplementsList/ClassOrInterfaceType[ ends-with(@Image, 'Service') or \"\n        + \"ends-with(@Image, 'DAO')]]\"\n        + \"[not(.[ ends-with(@Image, 'Impl')])]\";\n\n    public ServiceOrDaoClassShouldEndWithImplRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            I18nResources.getMessage(\"java.naming.ServiceOrDaoClassShouldEndWithImplRule.violation.msg\",\n                node.getImage()));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/naming/TestClassShouldEndWithTestNamingRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.rule.AbstractJUnitRule;\n\n/**\n * [Mandatory] Test cases shall be started with the class names to be tested and ended with Test.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class TestClassShouldEndWithTestNamingRule extends AbstractJUnitRule {\n    private static final String TEST_SUFFIX = \"Test\";\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (node.isAbstract() || node.isInterface() || node.isNested()) {\n            return super.visit(node, data);\n        }\n\n        List<ASTMethodDeclaration> m = node.findDescendantsOfType(ASTMethodDeclaration.class);\n        boolean testsFound = false;\n\n        if (m != null) {\n            for (ASTMethodDeclaration md : m) {\n                if (!isInInnerClassOrInterface(md) && isJUnitMethod(md, data)) {\n                    testsFound = true;\n                }\n            }\n        }\n\n        if ((testsFound) && (!(node.getImage().endsWith(TEST_SUFFIX)))) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                I18nResources.getMessage(\"java.naming.TestClassShouldEndWithTestNamingRule.violation.msg\",\n                    node.getImage()));\n        }\n\n        return super.visit(node, data);\n    }\n\n    private boolean isInInnerClassOrInterface(ASTMethodDeclaration md) {\n        ASTClassOrInterfaceDeclaration p = md.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);\n        return p != null && p.isNested();\n    }\n\n    @Override\n    public void setDescription(String description) {\n        super.setDescription(I18nResources.getMessageWithExceptionHandled(description));\n    }\n\n    @Override\n    public void setMessage(String message) {\n        super.setMessage(I18nResources.getMessageWithExceptionHandled(message));\n    }\n\n    @Override\n    public void addViolationWithMessage(Object data, Node node, String message) {\n        super.addViolationWithMessage(data, node, I18nResources.getMessageWithExceptionHandled(message));\n    }\n\n    @Override\n    public void addViolationWithMessage(Object data, Node node, String message, Object[] args) {\n        super.addViolationWithMessage(data, node,\n            String.format(I18nResources.getMessageWithExceptionHandled(message), args));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/oop/BigDecimalAvoidDoubleConstructorRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.oop;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTLiteral;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Avoid using the constructor BigDecimal(double) to convert double value to a BigDecimal object.\n *\n * @author zenghou.fw\n * @date 2019/04/02\n */\npublic class BigDecimalAvoidDoubleConstructorRule extends AbstractAliRule {\n\n    private static final String XPATH =\n        \"Expression/PrimaryExpression/PrimaryPrefix/AllocationExpression/Arguments[preceding-sibling::ClassOrInterfaceType[@Image = 'BigDecimal']]\"\n            + \"/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix\";\n\n    @Override\n    public Object visit(ASTVariableInitializer node, Object data) {\n        try {\n            List<Node> invocations = node.findChildNodesWithXPath(XPATH);\n            if (invocations == null || invocations.isEmpty()) {\n                return super.visit(node, data);\n            }\n            ASTPrimaryPrefix expression = (ASTPrimaryPrefix)invocations.get(0);\n\n            if (isDoubleLiteral(expression) || isDoubleVariable(expression)) {\n                    addViolationWithMessage(data, node,\n                        \"java.oop.BigDecimalAvoidDoubleConstructorRule.violation.msg\", null);\n            }\n\n        } catch (JaxenException e) {\n            throw new RuntimeException(\"XPath expression \" + XPATH + \" failed: \" + e.getLocalizedMessage(), e);\n        }\n        return super.visit(node, data);\n    }\n\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            \"java.oop.BigDecimalAvoidDoubleConstructorRule.violation.msg\");\n    }\n\n    private boolean isDoubleLiteral(ASTPrimaryPrefix node) {\n        ASTLiteral literal = node.getFirstChildOfType(ASTLiteral.class);\n        return literal != null && literal.isDoubleLiteral();\n    }\n\n    private boolean isDoubleVariable(ASTPrimaryPrefix node) {\n        ASTName name = node.getFirstChildOfType(ASTName.class);\n        return name != null && Double.class ==  name.getType();\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/oop/EqualsAvoidNullRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.oop;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.StringAndCharConstants;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTLiteral;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;\nimport net.sourceforge.pmd.lang.java.ast.Token;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Since NullPointerException can possibly be thrown while calling the equals method of Object,\n * equals should be invoked by a constant or an object that is definitely not null.\n *\n * @author zenghou.fw\n * @date 2016/11/29\n */\npublic class EqualsAvoidNullRule extends AbstractAliRule {\n\n    private static final String XPATH = \"//PrimaryExpression[\" + \"(PrimaryPrefix[Name[(ends-with(@Image, '.equals'))]]|\"\n        + \"PrimarySuffix[@Image='equals'])\"\n        + \"[(../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix) and \"\n        + \"( count(../PrimarySuffix/Arguments/ArgumentList/Expression) = 1 )]]\"\n        + \"[not(ancestor::Expression/ConditionalAndExpression//EqualityExpression[@Image='!=']//NullLiteral)]\"\n        + \"[not(ancestor::Expression/ConditionalOrExpression//EqualityExpression[@Image='==']//NullLiteral)]\";\n\n    private static final String INVOCATION_PREFIX_XPATH\n        = \"PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression[not(PrimarySuffix)]/PrimaryPrefix\";\n\n    private static final String METHOD_EQUALS = \"equals\";\n\n    @Override\n    public Object visit(ASTCompilationUnit node, Object data) {\n        try {\n            List<Node> equalsInvocations = node.findChildNodesWithXPath(XPATH);\n            if (equalsInvocations == null || equalsInvocations.isEmpty()) {\n                return super.visit(node, data);\n            }\n            for (Node invocation : equalsInvocations) {\n                // https://github.com/alibaba/p3c/issues/471\n                if (callerIsLiteral(invocation)) {\n                    return super.visit(node, data);\n                }\n\n                // if arguments of equals is complicate expression, skip the check\n                List<? extends Node> simpleExpressions = invocation.findChildNodesWithXPath(INVOCATION_PREFIX_XPATH);\n                if (simpleExpressions == null || simpleExpressions.isEmpty()) {\n                    return super.visit(node, data);\n                }\n\n                ASTPrimaryPrefix right = (ASTPrimaryPrefix)simpleExpressions.get(0);\n                if (right.getFirstChildOfType(ASTLiteral.class) != null) {\n                    ASTLiteral literal = right.getFirstChildOfType(ASTLiteral.class);\n                    if (literal.isStringLiteral()) {\n                        // other literals has no equals method, can not be flipped\n                        addRuleViolation(data, invocation);\n                    }\n                } else {\n                    ASTName name = right.getFirstChildOfType(ASTName.class);\n                    // TODO works only in current compilation file, by crossing files will be null\n                    boolean nameInvalid = name == null || name.getNameDeclaration() == null\n                        || name.getNameDeclaration().getNode() == null;\n                    if (nameInvalid) {\n                        return super.visit(node, data);\n                    }\n                    Node nameNode = name.getNameDeclaration().getNode();\n                    if ((nameNode instanceof ASTVariableDeclaratorId) && (nameNode.getNthParent(\n                        2) instanceof ASTFieldDeclaration)) {\n                        ASTFieldDeclaration field = (ASTFieldDeclaration)nameNode.getNthParent(2);\n                        if (NodeUtils.isConstant(field)) {\n                            addRuleViolation(data, invocation);\n                        }\n                    }\n                }\n            }\n        } catch (JaxenException e) {\n            throw new RuntimeException(\"XPath expression \" + XPATH + \" failed: \" + e.getLocalizedMessage(), e);\n        }\n        return super.visit(node, data);\n    }\n\n    private boolean callerIsLiteral(Node equalsInvocation) {\n        if (equalsInvocation instanceof ASTPrimaryExpression) {\n            ASTPrimaryPrefix caller = equalsInvocation.getFirstChildOfType(ASTPrimaryPrefix.class);\n            return caller != null && caller.getFirstChildOfType(ASTLiteral.class) != null;\n        }\n        return false;\n    }\n\n    private String getInvocationName(AbstractJavaNode javaNode) {\n        Token token = (Token)javaNode.jjtGetFirstToken();\n        StringBuilder sb = new StringBuilder(token.image).append(token.image);\n        while (token.next != null && token.next.image != null && !METHOD_EQUALS.equals(token.next.image)) {\n            token = token.next;\n            sb.append(token.image);\n        }\n        if (sb.charAt(sb.length() - 1) == StringAndCharConstants.DOT) {\n            sb.deleteCharAt(sb.length() - 1);\n        }\n        return sb.toString();\n    }\n\n    private void addRuleViolation(Object data, Node invocation) {\n        if (invocation instanceof AbstractJavaNode) {\n            AbstractJavaNode javaNode = (AbstractJavaNode)invocation;\n            addViolationWithMessage(data, invocation, \"java.oop.EqualsAvoidNullRule.violation.msg\",\n                new Object[] {getInvocationName(javaNode)});\n        } else {\n            addViolation(data, invocation);\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/oop/PojoMustOverrideToStringRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.oop;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractPojoRule;\nimport com.alibaba.p3c.pmd.lang.java.util.PojoUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTBlock;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTExtendsList;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] The toString method must be implemented in a POJO class. The super.toString method should be called\n * in front of the whole implementation if the current class extends another POJO class.\n *\n * @author zenghou.fw\n * @date 2016/11/25\n */\npublic class PojoMustOverrideToStringRule extends AbstractPojoRule {\n\n    private static final String XPATH = \"ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration\"\n        + \"[@Public='true' and MethodDeclarator[@Image='toString'] and \"\n        + \"MethodDeclarator[@Image='toString' and @ParameterCount='0']]\";\n\n    private static final String TOSTRING_XPATH = \"//PrimaryExpression[PrimaryPrefix[Name\"\n        + \"[(ends-with(@Image, '.toString'))]][\"\n        + \"(../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Literal[@StringLiteral\"\n        + \"='true'])\" + \" and ( count(../PrimarySuffix/Arguments/ArgumentList/Expression) = 1 )]]\"\n        + \"[not(ancestor::Expression/ConditionalAndExpression//EqualityExpression[@Image='!=']//NullLiteral)]\"\n        + \"[not(ancestor::Expression/ConditionalOrExpression//EqualityExpression[@Image='==']//NullLiteral)]\";\n\n    private static final String LOMBOK_NAME_XPATH = \"/Name[\"\n        + \"(@Image='Data' and //ImportDeclaration[@ImportedName='lombok.Data' or @ImportedName='lombok'])\"\n        + \" or (@Image='ToString' and //ImportDeclaration[@ImportedName='lombok.ToString' or @ImportedName='lombok'])\"\n        + \" or (@Image='lombok.Data') or (@Image='lombok.ToString')]\";\n\n    private static final String LOMBOK_XPATH = \"../Annotation/MarkerAnnotation\" + LOMBOK_NAME_XPATH\n        + \"|../Annotation/NormalAnnotation\" + LOMBOK_NAME_XPATH;\n\n    private static final String MESSAGE_KEY_PREFIX = \"java.oop.PojoMustOverrideToStringRule.violation.msg\";\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (node.isInterface()) {\n            return super.visit(node, data);\n        }\n\n        if (!isPojo(node)) {\n            return super.visit(node, data);\n        }\n        if (node.isAbstract() || withLombokAnnotation(node)) {\n            return super.visit(node, data);\n        }\n\n        if (!node.hasDescendantMatchingXPath(XPATH)) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                I18nResources.getMessage(MESSAGE_KEY_PREFIX + \".notostring\", node.getImage()));\n        } else {\n            checkForExtend(node, data);\n        }\n        return super.visit(node, data);\n    }\n\n    private void checkForExtend(ASTClassOrInterfaceDeclaration node, Object data) {\n    /*\n     * The super.toString method should be called in front of the whole implementation\n     * if the current class extends another POJO class\n     * -> this part not checked\n     */\n        ASTExtendsList extendsList = node.getFirstChildOfType(ASTExtendsList.class);\n        if (extendsList == null) {\n            return;\n        }\n        String baseName = extendsList.getFirstChildOfType(ASTClassOrInterfaceType.class).getImage();\n        if (!PojoUtils.isPojo(baseName)) {\n            return;\n        }\n        try {\n            // toString() definition\n            ASTMethodDeclaration toStringMethod = (ASTMethodDeclaration)node.findChildNodesWithXPath(XPATH).get(0);\n            ASTBlock block = toStringMethod.getBlock();\n            if (block.hasDescendantMatchingXPath(TOSTRING_XPATH)) {\n                addViolationWithMessage(data, block, MESSAGE_KEY_PREFIX + \".usesuper\");\n            }\n        } catch (JaxenException e) {\n            throw new RuntimeException(\"XPath expression \" + XPATH + \" failed: \" + e.getLocalizedMessage(), e);\n        }\n    }\n\n    /**\n     * Class with lombok @Data will be skipped\n     */\n    private boolean withLombokAnnotation(ASTClassOrInterfaceDeclaration node) {\n        return node.hasDescendantMatchingXPath(LOMBOK_XPATH);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/oop/PojoMustUsePrimitiveFieldRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.oop;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractPojoRule;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.VariableUtils;\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTType;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory]  Rules for using primitive data types and wrapper classes:\n * 1) Members of a POJO class must be wrapper classes.\n * 2) The return value and arguments of a RPC method must be wrapper classes.\n * 3) [Recommended] Local variables should be primitive data types.\n *\n * check only 1) here\n *\n * @author zenghou.fw\n * @date 2016/11/25\n */\npublic class PojoMustUsePrimitiveFieldRule extends AbstractPojoRule {\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (!isPojo(node)) {\n            return super.visit(node, data);\n        }\n        try {\n            List<Node> fields = node.findChildNodesWithXPath(\n                \"ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration\");\n\n            for (Node fieldNode : fields) {\n                ASTFieldDeclaration field = (ASTFieldDeclaration)fieldNode;\n                boolean shouldProcess = !field.isPublic() && !field.isStatic() && !field.isTransient();\n                if (!shouldProcess) {\n                    continue;\n                }\n                Class type = NodeUtils.getNodeType(field);\n                // TODO works only in current compilation file, by crossing files will be null\n                if (type != null && type.isPrimitive()) {\n                    addViolationWithMessage(data, field.getFirstDescendantOfType(ASTType.class),\n                        \"java.oop.PojoMustUsePrimitiveFieldRule.violation.msg\",\n                        new Object[] {VariableUtils.getVariableName(field)});\n                }\n            }\n        } catch (JaxenException e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/oop/PojoNoDefaultValueRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.oop;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractPojoRule;\nimport com.alibaba.p3c.pmd.lang.java.util.VariableUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] While defining POJO classes like DO, DTO, VO, etc., do not assign any default values to the members.\n *\n * @author zenghou.fw\n * @date 2016/11/22\n */\npublic class PojoNoDefaultValueRule extends AbstractPojoRule {\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (!isPojo(node)) {\n            return super.visit(node, data);\n        }\n        try {\n            List<Node> fields = node.findChildNodesWithXPath(\n                \"ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration\");\n\n            for (Node fieldNode : fields) {\n                ASTFieldDeclaration field = (ASTFieldDeclaration)fieldNode;\n                boolean shouldProcess = !field.isPublic() && !field.isFinal() && !field.isStatic() && !field\n                    .isVolatile() &&\n                    field.hasDescendantOfType(ASTVariableInitializer.class);\n                if (!shouldProcess) {\n                    continue;\n                }\n                ViolationUtils.addViolationWithPrecisePosition(this, field, data,\n                    I18nResources.getMessage(\"java.oop.PojoNoDefaultValueRule.violation.msg\",\n                        VariableUtils.getVariableName(field)));\n            }\n        } catch (JaxenException e) {\n            throw new RuntimeException(e.getMessage(), e);\n        }\n\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/oop/StringConcatRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.oop;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.NumberConstants;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTAdditiveExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTDoStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTForStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;\nimport net.sourceforge.pmd.lang.symboltable.NameDeclaration;\nimport org.jaxen.JaxenException;\n\n/**\n * [Recommended] Use the append method in StringBuilder inside a loop body when concatenating multiple strings.\n *\n * @author zenghou.fw\n * @date 2017/04/11\n */\npublic class StringConcatRule extends AbstractAliRule {\n\n    private static final String XPATH =\n        \"Statement/Block//Expression[preceding-sibling::AssignmentOperator]/AdditiveExpression[(@Image = '+') and \"\n            + \"count(./PrimaryExpression/PrimaryPrefix/Literal[@StringLiteral = 'true']) > 0]\";\n\n    @Override\n    public Object visit(ASTForStatement node, Object data) {\n        checkStringConcat(node, data, ASTForStatement.class);\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTWhileStatement node, Object data) {\n        checkStringConcat(node, data, ASTWhileStatement.class);\n        return super.visit(node, data);\n    }\n\n    @Override\n    public Object visit(ASTDoStatement node, Object data) {\n        checkStringConcat(node, data, ASTDoStatement.class);\n        return super.visit(node, data);\n    }\n\n    /**\n     * Find additive assignment with string literal, then check if the assigned variable defined out of the loop,\n     *\n     * @param node\n     * @param data\n     * @param nodeClass\n     */\n    private void checkStringConcat(Node node, Object data, Class nodeClass) {\n        try {\n            List<? extends Node> additiveNodes = node.findChildNodesWithXPath(XPATH);\n            for (Node additiveNode : additiveNodes) {\n                ASTAdditiveExpression additiveExpression = (ASTAdditiveExpression)additiveNode;\n                Node assignmentStatement = additiveExpression.getNthParent(2);\n                if (!(assignmentStatement instanceof ASTStatementExpression)) {\n                    continue;\n                }\n                List<Node> nodes = ((ASTStatementExpression)assignmentStatement)\n                    .findChildNodesWithXPath(\"PrimaryExpression/PrimaryPrefix/Name[@Image]\");\n                if (nodes == null || nodes.size() != NumberConstants.INTEGER_SIZE_OR_LENGTH_1) {\n                    continue;\n                }\n                NameDeclaration resultVar = ((ASTName)nodes.get(0)).getNameDeclaration();\n                if (resultVar != null && resultVar.getNode() != null) {\n                    boolean isDefinedInLoop = false;\n\n                    AbstractJavaNode loopStatement = (AbstractJavaNode)resultVar.getNode().getFirstParentOfType(\n                        nodeClass);\n\n                    while (loopStatement != null) {\n                        if (loopStatement == node) {\n                            isDefinedInLoop = true;\n                            break;\n                        }\n                        loopStatement = (AbstractJavaNode)loopStatement.getFirstParentOfType(nodeClass);\n                    }\n\n                    // if assigned variable defined in the loop then break\n                    if (isDefinedInLoop) {\n                        return;\n                    }\n                }\n                // arguments joint by \"+\"\n                for (int i = 0; i < additiveNode.jjtGetNumChildren(); i++) {\n                    Node firstArg = additiveNode.jjtGetChild(i);\n                    if (!(firstArg instanceof ASTPrimaryExpression)) {\n                        continue;\n                    }\n                    List<Node> names = ((ASTPrimaryExpression)firstArg).\n                        findChildNodesWithXPath(\"./PrimaryPrefix/Name[@Image]\");\n                    if (names == null || names.size() != NumberConstants.INTEGER_SIZE_OR_LENGTH_1) {\n                        continue;\n                    }\n                    NameDeclaration firstArgVar = ((ASTName)names.get(0)).getNameDeclaration();\n\n                    // concat self, e.g. a = a + b;\n                    if (resultVar == firstArgVar) {\n                        addViolation(data, additiveNode);\n                        break;\n                    }\n                }\n            }\n        } catch (JaxenException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            I18nResources.getMessage(\"java.oop.PojoMustOverrideToStringRule.violation.msg\"));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/oop/WrapperTypeEqualityRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.oop;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.NumberConstants;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\n\n/**\n * [Mandatory] The wrapper classes should be compared by equals method rather than by symbol of '==' directly.\n *\n * @author zenghou.fw\n * @date 2016/11/22\n */\npublic class WrapperTypeEqualityRule extends AbstractAliRule {\n\n    @Override\n    public Object visit(ASTEqualityExpression node, Object data) {\n        final String literalPrefix = \"PrimaryExpression/PrimaryPrefix/Literal\";\n        final String unaryExpression = \"UnaryExpression\";\n        // null presents in either side of \"==\" or \"!=\" means no violation\n        if (node.hasDescendantMatchingXPath(literalPrefix)\n            || node.hasDescendantMatchingXPath(unaryExpression)) {\n            return super.visit(node, data);\n        }\n\n        // possible elements around \"==\" are PrimaryExpression or UnaryExpression(e.g. a == -2)\n        List<ASTPrimaryExpression> expressions = node.findChildrenOfType(ASTPrimaryExpression.class);\n        if (expressions.size() == NumberConstants.INTEGER_SIZE_OR_LENGTH_2) {\n            // PMD can not resolve array length type, but only the\n            ASTPrimaryExpression left = expressions.get(0);\n            ASTPrimaryExpression right = expressions.get(1);\n            // if left is complex expression, skip\n            if (left.jjtGetNumChildren() > 1) {\n                return super.visit(node, data);\n            }\n            boolean bothArrayLength = isArrayLength(left) && isArrayLength(right);\n            boolean bothWrapperType = NodeUtils.isWrapperType(left) && NodeUtils.isWrapperType(right);\n\n            if (!bothArrayLength && bothWrapperType) {\n                addViolationWithMessage(data, node, \"java.oop.WrapperTypeEqualityRule.violation.msg\");\n            }\n        }\n\n        return super.visit(node, data);\n    }\n\n    private boolean isArrayLength(ASTPrimaryExpression expression) {\n        // assume expression like \"x.length\" is the length of array, field with name \"length\" may result in\n        // misrecognition\n        return \"length\".equals(expression.jjtGetLastToken().getImage())\n            && \".\".equals(expression.jjtGetFirstToken().getNext().getImage());\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/orm/IbatisMethodQueryForListRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.orm;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.VariableUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTLiteral;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport org.apache.commons.lang3.StringUtils;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] iBatis built in queryForList(String statementName, int start, int size) is not recommended.\n * Note: It may lead to OOM issue because its implementation is to retrieve all DB records of statementName's\n * corresponding SQL statement, then start, size subset is applied through subList.\n *\n * @author changle.lq\n * @date 2017/04/16\n */\npublic class IbatisMethodQueryForListRule extends AbstractAliRule {\n    private static final String SQL_MAP_CLIENT_IMPORT_FULL_NAME = \"com.ibatis.sqlmap.client.SqlMapClient\";\n    private static final String SQL_MAP_CLIENT_IMPORT_SIMPLE_NAME = \"com.ibatis.sqlmap.client.*\";\n    private static final String SQL_MAP_CLIENT_NAME = \"SqlMapClient\";\n    private static final String IBATIS_QUERY_FOR_LIST_METHOD_NAME = \".queryForList\";\n    private static final String PRIMARY_METHOD_NAME_XPATH = \"PrimaryPrefix/Name\";\n    private static final String PRIMARY_METHOD_ARGUMENT_XPATH\n        = \"PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Literal\";\n    private static final String FIELDS_XPATH = \"ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration\";\n    private static final int LITERALS_SIZE = 3;\n\n    @Override\n    public Object visit(ASTCompilationUnit node, Object data) {\n        boolean hasImportSqlMapClient = hasSqlMapClientImport(node.findChildrenOfType(ASTImportDeclaration.class));\n        if (!hasImportSqlMapClient) {\n            return super.visit(node, data);\n        }\n        List<ASTClassOrInterfaceDeclaration> classOrInterfaceDeclarations\n            = node.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class);\n        if (classOrInterfaceDeclarations == null || classOrInterfaceDeclarations.isEmpty()) {\n            return super.visit(node, data);\n        }\n        for (ASTClassOrInterfaceDeclaration classOrInterfaceDeclaration : classOrInterfaceDeclarations) {\n            visitAstClassOrInterfaceDeclaration(classOrInterfaceDeclaration, data);\n        }\n        return super.visit(node, data);\n    }\n\n    private void visitAstClassOrInterfaceDeclaration(ASTClassOrInterfaceDeclaration classOrInterfaceDeclaration,\n        Object data) {\n        try {\n            List<Node> fieldDeclarations = classOrInterfaceDeclaration.findChildNodesWithXPath(FIELDS_XPATH);\n            Set<String> sqlMapFields = getSqlMapFields(fieldDeclarations);\n            if (sqlMapFields.isEmpty()) {\n                return;\n            }\n            List<ASTPrimaryExpression> primaryExpressions = classOrInterfaceDeclaration.findDescendantsOfType(\n                ASTPrimaryExpression.class);\n            for (ASTPrimaryExpression primaryExpression : primaryExpressions) {\n                visitPrimaryExpression(primaryExpression, data, sqlMapFields);\n            }\n        } catch (JaxenException ignored) {\n        }\n    }\n\n    private Set<String> getSqlMapFields(List<Node> fieldDeclarations) {\n        if (fieldDeclarations == null || fieldDeclarations.isEmpty()) {\n            return Collections.emptySet();\n        }\n        Set<String> set = new HashSet<>();\n        for (Node node : fieldDeclarations) {\n            ASTFieldDeclaration fieldDeclaration = (ASTFieldDeclaration)node;\n            if (sqlMapClientField(fieldDeclaration)) {\n                set.add(VariableUtils.getVariableName(fieldDeclaration));\n            }\n        }\n        return set;\n    }\n\n    /**\n     * if there is no introduction of related packages, skip the inspection\n     * The import statement is generally at the start of the class, do some cleaning\n     */\n    private boolean hasSqlMapClientImport(List<ASTImportDeclaration> importDeclarations) {\n        if (importDeclarations == null || importDeclarations.isEmpty()) {\n            return false;\n        }\n        for (ASTImportDeclaration importDeclaration : importDeclarations) {\n            ASTName astName = importDeclaration.getFirstChildOfType(ASTName.class);\n            boolean hasImport = astName != null && (SQL_MAP_CLIENT_IMPORT_FULL_NAME.equals(astName.getImage())\n                || SQL_MAP_CLIENT_IMPORT_SIMPLE_NAME.equals(astName.getImage()));\n            if (hasImport) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * check if any method matches queryForList(String statementName,int start,int size)\n     */\n    private void visitPrimaryExpression(ASTPrimaryExpression node, Object data,\n        Set<String> sqlMapFields) throws JaxenException {\n        List<Node> astNames = node.findChildNodesWithXPath(PRIMARY_METHOD_NAME_XPATH);\n        for (Node astName : astNames) {\n            String methodName = astName.getImage();\n            //method name not match\n            if (!(StringUtils.isNotEmpty(methodName) && methodName.contains(\n                IBATIS_QUERY_FOR_LIST_METHOD_NAME))) {\n                continue;\n            }\n            String methodInvokeName = methodName.substring(0,\n                methodName.indexOf(IBATIS_QUERY_FOR_LIST_METHOD_NAME));\n            //the method caller is empty\n            if (StringUtils.isEmpty(methodInvokeName)) {\n                continue;\n            }\n\n            //the method caller not matches SqlMapClient\n            if (!sqlMapFields.contains(methodInvokeName)) {\n                continue;\n            }\n            //method parameters not match\n            List<Node> literals = node.findChildNodesWithXPath(PRIMARY_METHOD_ARGUMENT_XPATH);\n            if (literals == null || (literals.size() != LITERALS_SIZE)) {\n                continue;\n            }\n            boolean firstMethodArgumentString = \"java.lang.String\".equals(\n                ((ASTLiteral)(literals.get(0))).getType().getName());\n            boolean secondMethodArgumentInt = \"int\".equals(\n                ((ASTLiteral)(literals.get(1))).getType().getName());\n            boolean thirdMethodArgumentInt = \"int\".equals(\n                ((ASTLiteral)(literals.get(2))).getType().getName());\n            //if the parameter name and method name all matching, that is a violation of the rules\n            if (firstMethodArgumentString && secondMethodArgumentInt\n                && thirdMethodArgumentInt) {\n                ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                    I18nResources.getMessage(\"java.naming.IbatisMethodQueryForListRule.violation.msg\"));\n            }\n\n        }\n    }\n\n    /**\n     * if the attributes of a class defines the SqlMapClient object,collect these object name\n     */\n    private boolean sqlMapClientField(ASTFieldDeclaration node) {\n        try {\n            List<Node> astClassOrInterfaceTypes = node.findChildNodesWithXPath(\n                \"Type/ReferenceType/ClassOrInterfaceType\");\n            //find  the SqlMapClient attribute node, collect these node's parent to sqlMapClientTypeFieldList\n            for (Node astClassOrInterfaceType : astClassOrInterfaceTypes) {\n                String fieldTypeName = astClassOrInterfaceType.getImage();\n                if (SQL_MAP_CLIENT_NAME.equals(fieldTypeName)\n                    || SQL_MAP_CLIENT_IMPORT_FULL_NAME.equals(fieldTypeName)) {\n                    return true;\n                }\n            }\n        } catch (JaxenException ignore) {\n        }\n        return false;\n\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/other/AvoidApacheBeanUtilsCopyRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * Avoid using *Apache Beanutils* to copy attributes.\n * Note: *Spring BeanUtils* and *Cglib BeanCopier* are recommended to be used, which have better performance.\n * \n * @author keriezhang\n * @date 2016/12/14\n *\n */\npublic class AvoidApacheBeanUtilsCopyRule extends AbstractXpathRule {\n    private static final String XPATH =\n            \"//PrimaryPrefix/Name[@Image='BeanUtils.copyProperties' and \"\n            + \"//ImportDeclaration[@ImportedName='org.apache.commons.beanutils.BeanUtils']]\";\n\n    public AvoidApacheBeanUtilsCopyRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/other/AvoidDoubleOrFloatEqualCompareRule.java",
    "content": "package com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\nimport net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\n\nimport java.util.List;\n\n/**\n * @author changle.lq\n * @date 2018/12/12\n */\npublic class AvoidDoubleOrFloatEqualCompareRule extends AbstractAliRule {\n\n    private static final String FLOAT = \"float\";\n    private static final String DOUBLE = \"double\";\n    private static final int LIST_SIZE = 2;\n\n    @Override\n    public Object visit(ASTEqualityExpression node, Object data) {\n        List<ASTPrimaryExpression> list = node.findDescendantsOfType(ASTPrimaryExpression.class);\n        if (list.size() != LIST_SIZE) {\n            return super.visit(node, data);\n        }\n\n        ASTPrimaryExpression left = list.get(0);\n        ASTPrimaryExpression right = list.get(1);\n        Class<?> leftType = left.getType();\n        Class<?> rightType = right.getType();\n        if (leftType == null || rightType == null) {\n            return super.visit(node, data);\n        }\n\n        if (FLOAT.equals(leftType.getName()) && FLOAT.equals(rightType.getName())) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data);\n        } else if (DOUBLE.equals(leftType.getName()) && DOUBLE.equals(rightType.getName())) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data);\n        }\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/other/AvoidMissUseOfMathRandomRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * [Mandatory] The return type of Math.random() is double, value range is 0&lt;=x&lt;1 (0 is possible).\n * If a random integer is required, do not multiply x by 10 then round the result.\n * The correct way is to use nextInt or nextLong method which belong to Random Object.\n *\n * @author keriezhang\n * @date 2017/04/14\n */\npublic class AvoidMissUseOfMathRandomRule extends AbstractXpathRule {\n\n    private static final String XPATH =\n        \"//PrimaryExpression[./PrimaryPrefix/Name[@Image='Math.random'] and \"\n            + \"../../MultiplicativeExpression/PrimaryExpression/PrimaryPrefix/Literal[matches(@Image, '^\\\\d+$')] and \"\n            + \"../../../../../../CastExpression/Type/PrimitiveType[matches(@Image, '^(int|long)$')]\"\n            + \"]\";\n\n    public AvoidMissUseOfMathRandomRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/other/AvoidNewDateGetTimeRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n * Use System.currentTimeMillis() to get the current millisecond. Do not use new Date().getTime().\n *\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class AvoidNewDateGetTimeRule extends AbstractXpathRule {\n\n    private static final String XPATH =\n        \"//PrimaryExpression\"\n            + \"[\"\n            + \"PrimaryPrefix/AllocationExpression/ClassOrInterfaceType[@Image='Date'] and \"\n            + \"PrimaryPrefix/AllocationExpression/Arguments[@ArgumentCount=0] and \"\n            + \"PrimarySuffix[@Image='getTime'] and \"\n            + \"PrimarySuffix/Arguments[@ArgumentCount=0]\"\n            + \"]\";\n\n    public AvoidNewDateGetTimeRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n            I18nResources.getMessage(\"java.other.AvoidNewDateGetTimeRule.violation.msg\"));\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/other/AvoidPatternCompileInMethodRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.util.VariableUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;\n\n/**\n * When using regex, precompile needs to be done in order to increase the matching performance.\n * Note: Do not define Pattern pattern = Pattern.compile(.); within method body.\n *\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class AvoidPatternCompileInMethodRule extends AbstractXpathRule {\n    /**\n     * The parameter of Pattern.compile cannot be a string literal.\n     */\n    private static final String XPATH = \"//MethodDeclaration//PrimaryExpression[\"\n        + \"PrimaryPrefix/Name[@Image='Pattern.compile'] and \"\n        + \"PrimarySuffix/Arguments/ArgumentList/Expression/\"\n        + \"PrimaryExpression/PrimaryPrefix/Literal[@StringLiteral='true']]\";\n\n    public AvoidPatternCompileInMethodRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        ASTLocalVariableDeclaration localVariableDeclaration = node.getFirstParentOfType(\n            ASTLocalVariableDeclaration.class);\n        if (localVariableDeclaration == null) {\n            super.addViolation(data, node, arg);\n        } else {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                I18nResources.getMessage(\"java.other.AvoidPatternCompileInMethodRule.violation.msg\",\n                    VariableUtils.getVariableName(localVariableDeclaration)));\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/other/MethodTooLongRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeSortUtils;\nimport com.alibaba.p3c.pmd.lang.java.util.ViolationUtils;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTAnnotation;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;\nimport net.sourceforge.pmd.lang.java.ast.Comment;\nimport net.sourceforge.pmd.lang.java.ast.FormalComment;\nimport net.sourceforge.pmd.lang.java.ast.MultiLineComment;\nimport net.sourceforge.pmd.lang.java.ast.SingleLineComment;\nimport net.sourceforge.pmd.lang.java.ast.Token;\n\n/**\n * [Recommended] The total number of lines for a method should not be more than 80.\n * Note: The total number of lines, including the method signature, closing brace, codes, blank lines,\n * line breaks and any invisible lines, should not be more than 80 (comments are not included).\n *\n * @author keriezhang\n * @date 2018/1/9\n */\npublic class MethodTooLongRule extends AbstractAliRule {\n\n    private static final int MAX_LINE_COUNT = 80;\n    private static final String ANNOTATION_PREFIX = \"@\";\n\n    /**\n     * sortedMap will be reinitialized for each source file.\n     */\n    private SortedMap<Integer, Node> sortedNodeAndComment;\n\n    @Override\n    public Object visit(ASTCompilationUnit cUnit, Object data) {\n        sortedNodeAndComment = orderedCommentsAndExpressions(cUnit);\n        return super.visit(cUnit, data);\n    }\n\n    @Override\n    public Object visit(ASTMethodDeclaration node, Object data) {\n        // Include method modifiers.\n        ASTClassOrInterfaceBodyDeclaration classOrInterfaceBodyDecl =\n            (ASTClassOrInterfaceBodyDeclaration)node.jjtGetParent();\n\n        int startLine = classOrInterfaceBodyDecl.getBeginLine();\n        int endLine = classOrInterfaceBodyDecl.getEndLine();\n\n        Node firstChild = classOrInterfaceBodyDecl.jjtGetChild(0);\n        // Method has annotation\n        if (firstChild instanceof ASTAnnotation) {\n            Token firstToken = (Token)classOrInterfaceBodyDecl.jjtGetFirstToken();\n            // If annotation is before modifier, exclude the annotation.\n            if (ANNOTATION_PREFIX.equals(firstToken.image)) {\n                ASTAnnotation annotation = (ASTAnnotation)firstChild;\n                Token lastToken = (Token)annotation.jjtGetLastToken();\n\n                // First token after annotation. The same line or next line after annotation.\n                Token next = lastToken.next;\n                startLine = next.beginLine;\n            }\n        }\n\n        // Get comment line count.\n        int commentLineCount = getCommentLineCount(node);\n\n        if (endLine - startLine - commentLineCount + 1 > MAX_LINE_COUNT) {\n            ViolationUtils.addViolationWithPrecisePosition(this, node, data,\n                I18nResources.getMessage(\"java.other.MethodTooLongRule.violation.msg\", node.getName()));\n        }\n        return data;\n    }\n\n    /**\n     * Order comments and expressions.\n     *\n     * @param cUnit compilation unit\n     * @return sorted comments and expressions\n     */\n    protected SortedMap<Integer, Node> orderedCommentsAndExpressions(ASTCompilationUnit cUnit) {\n\n        SortedMap<Integer, Node> itemsByLineNumber = new TreeMap<>();\n\n        // expression nodes\n        List<ASTExpression> expressionNodes = cUnit.findDescendantsOfType(ASTExpression.class);\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, expressionNodes);\n\n        NodeSortUtils.addNodesToSortedMap(itemsByLineNumber, cUnit.getComments());\n\n        return itemsByLineNumber;\n    }\n\n    /**\n     * Get number of comment lines\n     *\n     * @param methodDecl\n     * @return\n     */\n    private int getCommentLineCount(ASTMethodDeclaration methodDecl) {\n        int lineCount = 0;\n        AbstractJavaNode lastNode = null;\n\n        for (Entry<Integer, Node> entry : sortedNodeAndComment.entrySet()) {\n            Node value = entry.getValue();\n            if (value.getBeginLine() <= methodDecl.getBeginLine()) {\n                continue;\n            }\n            if (value.getBeginLine() > methodDecl.getEndLine()) {\n                break;\n            }\n\n            // value should be either expression or comment.\n            if (value instanceof AbstractJavaNode) {\n                lastNode = (AbstractJavaNode)value;\n            } else if (value instanceof FormalComment || value instanceof MultiLineComment) {\n                Comment comment = (Comment)value;\n                lineCount += comment.getEndLine() - comment.getBeginLine() + 1;\n            } else if (value instanceof SingleLineComment) {\n                SingleLineComment singleLineComment = (SingleLineComment)value;\n                // Comment may in the same line with node.\n                if (lastNode == null || singleLineComment.getBeginLine() != lastNode.getBeginLine()) {\n                    lineCount += 1;\n                }\n            }\n        }\n        return lineCount;\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/other/UseRightCaseForDateFormatRule.java",
    "content": "package com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;\nimport net.sourceforge.pmd.lang.java.ast.ASTLiteral;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport org.apache.commons.lang3.StringUtils;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] When doing date formatting, \"y\" should be written in lowercase for \"year\" in a pattern statement.\n *\n * Note: When doing date formatting, \"yyyy\" represents the day in which year, while \"YYYY\" represents the week in which\n * year (a concept introduced in JDK7). If a week is across two years, the returning \"YYYY\"represents the next year.\n * Some more points need to be notices:\n * Uppercase \"M\" stands for month.\n * Lowercase \"m\" stands for minute.\n * Uppercase \"H\" stands for 24-hour clock.\n * Lowercase \"h\" stands for 12-hour clock.\n *\n * Positive Example: Example pattern for date formatting:\n * new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n *\n * Counter Example: Someone applied \"YYYY/MM/dd\" pattern for date formatting, and the execution result of 2017/12/31 was\n * 2018/12/31, leading to a serious failure.\n *\n * @author huawen.phw\n * @date 2018/1/9\n */\npublic class UseRightCaseForDateFormatRule extends AbstractXpathRule {\n\n    private static final String NEW_XPATH\n        = \"//AllocationExpression/ClassOrInterfaceType[@Image='SimpleDateFormat']/../Arguments/ArgumentList\"\n        + \"/Expression/PrimaryExpression/PrimaryPrefix/*\";\n    private static final String LOW_CASE_4Y = \"yyyy\";\n    private static final String LOW_CASE_2Y = \"yy\";\n    private static final String START_QUOTE = \"\\\"\";\n\n    public UseRightCaseForDateFormatRule() {\n        setXPath(NEW_XPATH);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        checkNode(node, data);\n    }\n\n    /**\n     * 暂只检查4个y和2个y开头的日期格式化字符串参数，不考虑其他类型\n     *\n     * @param argNode\n     * @param data\n     */\n    private void checkNode(Node argNode, Object data) {\n        String image = \"\";\n        if (argNode instanceof ASTLiteral) {\n            image = argNode.getImage();\n        }\n        // 限定只验证字符串，其他如参数、变量等均不考虑\n        if (StringUtils.isEmpty(image) || !image.startsWith(START_QUOTE)) {\n            return;\n        }\n        image = image.replace(\"\\\"\", \"\");\n        String lowerCaseTmp = image.toLowerCase();\n        if (!image.startsWith(LOW_CASE_4Y) && lowerCaseTmp.startsWith(LOW_CASE_4Y)) {\n            addViolationWithMessage(data, argNode,\n                \"java.other.UseRightCaseForDateFormatRule.rule.msg\",\n                new Object[] {image});\n        } else if (!image.startsWith(LOW_CASE_2Y) && lowerCaseTmp.startsWith(LOW_CASE_2Y)) {\n            addViolationWithMessage(data, argNode,\n                \"java.other.UseRightCaseForDateFormatRule.rule.msg\",\n                new Object[] {image});\n        } else {\n            //暂不考虑\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/set/ClassCastExceptionWithSubListToArrayListRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.set;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Do not cast subList in class ArrayList, otherwise ClassCastException will be\n * thrown：java.util.RandomAccessSubList\n * cannot be cast to java.util.ArrayList ;\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n */\npublic class ClassCastExceptionWithSubListToArrayListRule extends AbstractAliRule {\n\n    private static final String XPATH =\n        \"//CastExpression[Type/ReferenceType/ClassOrInterfaceType[@Image = \"\n            + \"\\\"ArrayList\\\"]]/PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image,'.subList')]\";\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (node.isInterface()) {\n            return data;\n        }\n        try {\n            List<Node> nodes = node.findChildNodesWithXPath(XPATH);\n            for (Node item : nodes) {\n                if (!(item instanceof ASTName)) {\n                    continue;\n                }\n                addViolationWithMessage(data, item,\n                    \"java.set.ClassCastExceptionWithSubListToArrayListRule.violation.msg\",\n                    new Object[] {item.getImage()});\n            }\n        } catch (JaxenException e) {\n            e.printStackTrace();\n        }\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/set/ClassCastExceptionWithToArrayRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.set;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Do not use toArray method without arguments. Since the return type is Object[], ClassCastException will\n * be thrown when casting it to a different array type。\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n */\npublic class ClassCastExceptionWithToArrayRule extends AbstractAliRule {\n\n    private static final String XPATH\n        = \"//CastExpression[Type/ReferenceType/ClassOrInterfaceType[@Image !=\\\"Object\\\"]]/PrimaryExpression\";\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (node.isInterface()) {\n            return data;\n        }\n        try {\n            List<Node> nodes = node.findChildNodesWithXPath(XPATH);\n            for (Node item : nodes) {\n                if (!(item instanceof ASTPrimaryExpression)) {\n                    continue;\n                }\n                ASTPrimaryExpression primaryExpression = (ASTPrimaryExpression)item;\n                List<ASTPrimaryPrefix> primaryPrefixs =\n                    primaryExpression.findChildrenOfType(ASTPrimaryPrefix.class);\n                List<ASTPrimarySuffix> primarySuffixs =\n                    primaryExpression.findChildrenOfType(ASTPrimarySuffix.class);\n                if (primaryPrefixs == null || primarySuffixs == null || primaryPrefixs.isEmpty()\n                    || primarySuffixs.isEmpty()) {\n                    continue;\n                }\n                ASTPrimaryPrefix prefix = primaryPrefixs.get(0);\n                ASTPrimarySuffix suffix = primarySuffixs.get(0);\n                if (prefix.jjtGetNumChildren() == 0) {\n                    continue;\n                }\n                Node prefixChildNode = prefix.jjtGetChild(0);\n                String childName = prefixChildNode.getImage();\n                if (childName == null) {\n                    continue;\n                }\n                if (childName.endsWith(\".toArray\") && suffix.getArgumentCount() == 0\n                    && primarySuffixs.size() == 1) {\n                    addViolationWithMessage(data, item,\n                        \"java.set.ClassCastExceptionWithToArrayRule.violation.msg\",\n                        new Object[] {childName});\n                }\n            }\n\n        } catch (JaxenException e) {\n            e.printStackTrace();\n        }\n        return super.visit(node, data);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/set/CollectionInitShouldAssignCapacityRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.set;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\nimport com.alibaba.p3c.pmd.lang.java.util.namelist.NameListConfig;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTArguments;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport org.jaxen.JaxenException;\n\n/**\n * [Recommended] Set a size when initializing a collection if possible.\n *\n * @author shengfang.gsf\n * @date 2017/04/06\n */\npublic class CollectionInitShouldAssignCapacityRule extends AbstractAliRule {\n\n    /**\n     * Black List,will increase ArrayList, HashSet etc follow-up\n     */\n    private final static List<String> COLLECTION_LIST = NameListConfig.NAME_LIST_SERVICE\n        .getNameList(CollectionInitShouldAssignCapacityRule.class.getSimpleName(), \"COLLECTION_TYPE\");\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        try {\n            // find Collection initialization\n            for (String collectionType : COLLECTION_LIST) {\n                visitByCollections(node, data, collectionType);\n            }\n        } catch (JaxenException e) {\n            e.printStackTrace();\n        }\n        return super.visit(node, data);\n    }\n\n    private void visitByCollections(ASTClassOrInterfaceDeclaration node, Object data, String collectionType)\n        throws JaxenException {\n        String collectionArgXpath =\n            \"//AllocationExpression/ClassOrInterfaceType[@Image='\" + collectionType + \"']/../Arguments\";\n        List<Node> argumentsNodes = node.findChildNodesWithXPath(collectionArgXpath);\n\n        for (Node argNode : argumentsNodes) {\n            if (!(argNode instanceof ASTArguments)) {\n                continue;\n            }\n            // filter not inner  method\n            if (argNode.getFirstParentOfType(ASTMethodDeclaration.class) == null) {\n                continue;\n            }\n            ASTArguments argumentNode = (ASTArguments)argNode;\n            Integer count = argumentNode.getArgumentCount();\n            // judge whether parameters have  initial size\n            if (count == 0) {\n                addViolationWithMessage(data, argNode,\n                    \"java.set.CollectionInitShouldAssignCapacityRule.violation.msg\",\n                    new Object[] {collectionType});\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/set/ConcurrentExceptionWithModifyOriginSubListRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.set;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTBlock;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] When using subList, be careful to modify the size of original list. It might cause\n * ConcurrentModificationException when performing traversing, adding or deleting on the subList.\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n */\npublic class ConcurrentExceptionWithModifyOriginSubListRule extends AbstractAliRule {\n\n    private final static String ADD = \".add\";\n    private final static String REMOVE = \".remove\";\n    private final static String CLEAR = \".clear\";\n    private final static String XPATH\n        = \"//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='List']]/VariableInitializer\"\n        + \"/Expression/PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image,'.subList')]\";\n    private final static String CHILD_XPATH\n        = \"BlockStatement/Statement/StatementExpression/PrimaryExpression/PrimaryPrefix/Name\";\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (node.isInterface()) {\n            return data;\n        }\n        try {\n            List<Node> nodes = node.findChildNodesWithXPath(XPATH);\n            for (Node item : nodes) {\n                if (!(item instanceof ASTName)) {\n                    continue;\n                }\n                String valName = getBeforeSubListVal(item.getImage());\n                ASTBlock blockNode = item.getFirstParentOfType(ASTBlock.class);\n                if (blockNode == null || valName == null) {\n                    continue;\n                }\n                List<Node> blockNodes = blockNode.findChildNodesWithXPath(CHILD_XPATH);\n\n                for (Node blockItem : blockNodes) {\n                    // adding or deleting on the subList result is forbidden\n                    if (blockItem.getBeginLine() < item.getBeginLine()) {\n                        continue;\n                    }\n                    if (checkBlockNodesValid(valName, blockItem)) {\n                        addViolationWithMessage(data, blockItem,\n                            \"java.set.ConcurrentExceptionWithModifyOriginSubListRule.violation.msg\",\n                            new Object[] {blockItem.getImage()});\n                    }\n                }\n\n            }\n        } catch (JaxenException e) {\n            e.printStackTrace();\n        }\n        return super.visit(node, data);\n    }\n\n    /**\n     * Find subList original variable\n     *\n     * @param image\n     * @return\n     */\n    private String getBeforeSubListVal(String image) {\n        return image == null ? null : image.substring(0, image.indexOf(\".\"));\n    }\n\n    /**\n     * Only to find out whether there is any violation within the scope of the  method\n     *\n     * @param variableName\n     * @param item\n     * @return\n     * @throws JaxenException\n     */\n    private boolean checkBlockNodesValid(String variableName, Node item) {\n        if (item instanceof ASTName) {\n            String name = item.getImage();\n            if (judgeName(name, variableName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * judge name equals to  t.add / t.remove / t.clear\n     *\n     * @param name\n     * @param variableName\n     * @return\n     */\n    private boolean judgeName(String name, String variableName) {\n        return name.equals(variableName + ADD) || name.equals(variableName + REMOVE)\n            || name.equals(variableName + CLEAR);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/set/DontModifyInForeachCircleRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.set;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTForStatement;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Do not remove or add elements to a collection in a foreach loop. Please use Iterator to remove an item.\n * Iterator object should be synchronized when executing concurrent operations.\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n */\npublic class DontModifyInForeachCircleRule extends AbstractAliRule {\n\n    private final static String ADD = \".add\";\n    private final static String REMOVE = \".remove\";\n    private final static String CLEAR = \".clear\";\n    private final static String XPATH = \"//ForStatement/Expression/PrimaryExpression/PrimaryPrefix/Name\";\n    private final static String CHILD_XPATH\n        = \"Statement/Block/BlockStatement/Statement/StatementExpression/PrimaryExpression/PrimaryPrefix/Name\";\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (node.isInterface()) {\n            return data;\n        }\n        try {\n            List<Node> nodes = node.findChildNodesWithXPath(XPATH);\n            for (Node item : nodes) {\n                if (!(item instanceof ASTName)) {\n                    continue;\n                }\n                String variableName = item.getImage();\n                if (variableName == null) {\n                    continue;\n                }\n                ASTForStatement forStatement = item.getFirstParentOfType(ASTForStatement.class);\n                List<Node> blockNodes = forStatement.findChildNodesWithXPath(CHILD_XPATH);\n                for (Node blockItem : blockNodes) {\n                    if (!(blockItem instanceof ASTName)) {\n                        continue;\n                    }\n                    if (judgeName(blockItem.getImage(), variableName)) {\n                        addViolationWithMessage(data, blockItem,\n                            \"java.set.DontModifyInForeachCircleRule.violation.msg\",\n                            new Object[] {blockItem.getImage()});\n                    }\n                }\n            }\n        } catch (JaxenException e) {\n            e.printStackTrace();\n        }\n        return super.visit(node, data);\n    }\n\n    private boolean judgeName(String name, String variableName) {\n        return name != null && (name.equals(variableName + ADD) ||\n            name.equals(variableName + REMOVE) || name.equals(variableName + CLEAR));\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/set/UnsupportedExceptionWithModifyAsListRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.set;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTBlock;\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\nimport org.jaxen.JaxenException;\n\n/**\n * [Mandatory] Do not use methods which will modify the list after using Arrays.asList to convert array to list,\n * otherwise methods like add/remove/clear will throw UnsupportedOperationException.\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n */\npublic class UnsupportedExceptionWithModifyAsListRule extends AbstractAliRule {\n\n    private final static String ADD = \".add\";\n    private final static String REMOVE = \".remove\";\n    private final static String CLEAR = \".clear\";\n    private final static String XPATH\n        = \"//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='List']]/VariableInitializer\"\n        + \"/Expression/PrimaryExpression/PrimaryPrefix/Name[@Image='Arrays.asList']\";\n    private final static String CHILD_XPATH\n        = \"BlockStatement/Statement/StatementExpression/PrimaryExpression/PrimaryPrefix/Name\";\n\n    @Override\n    public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {\n        if (node.isInterface()) {\n            return data;\n        }\n        try {\n            // find Array.asList variable\n            List<Node> nodes = node.findChildNodesWithXPath(XPATH);\n            for (Node item : nodes) {\n                if (!(item instanceof ASTName)) {\n                    continue;\n                }\n                List<ASTVariableDeclarator> parents =\n                    item.getParentsOfType(ASTVariableDeclarator.class);\n                if (parents == null || parents.size() == 0 || parents.size() > 1) {\n                    continue;\n                }\n                ASTVariableDeclarator declarator = parents.get(0);\n                ASTVariableDeclaratorId variableName =\n                    declarator.getFirstChildOfType(ASTVariableDeclaratorId.class);\n\n                String valName = variableName.getImage();\n                // find Variable scope code block\n                ASTBlock blockNode = variableName.getFirstParentOfType(ASTBlock.class);\n                if (blockNode == null || valName == null) {\n                    continue;\n                }\n                List<Node> blockNodes = blockNode.findChildNodesWithXPath(CHILD_XPATH);\n                // variable.add .removed is forbbiden.\n                for (Node blockItem : blockNodes) {\n                    if (blockItem.getBeginLine() < item.getBeginLine()) {\n                        continue;\n                    }\n                    if (checkBlockNodesValid(valName, blockItem)) {\n                        addViolationWithMessage(data, blockItem,\n                            \"java.set.UnsupportedExceptionWithModifyAsListRule.violation.msg\",\n                            new Object[] {blockItem.getImage()});\n                    }\n                }\n\n            }\n        } catch (JaxenException e) {\n            e.printStackTrace();\n        }\n        return super.visit(node, data);\n    }\n\n    /**\n     * Only to find out whether there is any violation within the scope of the corresponding method\n     *\n     * @param variableName\n     * @param item\n     * @return\n     * @throws JaxenException\n     */\n    private boolean checkBlockNodesValid(String variableName, Node item) {\n        if (item instanceof ASTName) {\n            String name = item.getImage();\n            if (judgeName(name, variableName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * judge name equels t.add t.remove t.clear\n     *\n     * @param name\n     * @param variableName\n     * @return\n     */\n    private boolean judgeName(String name, String variableName) {\n        return name.equals(variableName + ADD) || name.equals(variableName + REMOVE)\n            || name.equals(variableName + CLEAR);\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/util/NodeSortUtils.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.util;\n\nimport java.util.List;\nimport java.util.SortedMap;\n\nimport net.sourceforge.pmd.lang.ast.Node;\n\n/**\n *\n * @author keriezhang\n * @date 2016/11/21\n *\n */\npublic class NodeSortUtils {\n\n    /**\n     * add node to SortedMap with sequence to determine comment location\n     * \n     * @param map sorted map\n     * @param nodes nodes\n     */\n    public static void addNodesToSortedMap(SortedMap<Integer, Node> map, List<? extends Node> nodes) {\n        for (Node node : nodes) {\n            map.put(generateIndex(node), node);\n        }\n    }\n\n    /**\n     * set order according to node begin line and begin column\n     * @param node node to sort\n     * @return generated index\n     */\n    public static int generateIndex(Node node) {\n        return (node.getBeginLine() << 16) + node.getBeginColumn();\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/rule/util/NodeUtils.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.util;\n\nimport java.util.concurrent.locks.Lock;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTName;\nimport net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\nimport net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessTypeNode;\nimport net.sourceforge.pmd.lang.java.ast.Token;\nimport net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;\n\n/**\n * @author caikang\n * @date 2016/11/16\n */\npublic class NodeUtils {\n    public static final String LOCK_NAME = \"lock\";\n    public static final String LOCK_INTERRUPTIBLY_NAME = \"lockInterruptibly\";\n    public static final String UN_LOCK_NAME = \"unlock\";\n\n    public static boolean isParentOrSelf(Node descendant, Node ancestor) {\n        if (descendant == ancestor) {\n            return true;\n        }\n        if (descendant == null || ancestor == null) {\n            return false;\n        }\n        Node parent = descendant.jjtGetParent();\n        while (parent != ancestor && parent != null) {\n            parent = parent.jjtGetParent();\n        }\n        return parent == ancestor;\n    }\n\n    /**\n     * TODO optimize\n     *\n     * @param expression expression\n     * @return true if wrapper type\n     */\n    public static boolean isWrapperType(ASTPrimaryExpression expression) {\n        return TypeHelper.isA(expression, Integer.class)\n            || TypeHelper.isA(expression, Long.class)\n            || TypeHelper.isA(expression, Boolean.class)\n            || TypeHelper.isA(expression, Byte.class)\n            || TypeHelper.isA(expression, Double.class)\n            || TypeHelper.isA(expression, Short.class)\n            || TypeHelper.isA(expression, Float.class)\n            || TypeHelper.isA(expression, Character.class);\n    }\n\n    public static boolean isConstant(ASTFieldDeclaration field) {\n        return field != null && field.isStatic() && field.isFinal();\n    }\n\n    public static Class<?> getNodeType(AbstractJavaAccessTypeNode node) {\n        return node == null ? null : node.getType();\n    }\n\n    public static boolean isLockStatementExpression(ASTStatementExpression statementExpression) {\n        return isLockTypeAndMethod(statementExpression, LOCK_NAME);\n    }\n\n    public static boolean isUnLockStatementExpression(ASTStatementExpression statementExpression) {\n        return isLockTypeAndMethod(statementExpression, UN_LOCK_NAME);\n    }\n\n    private static boolean isLockTypeAndMethod(ASTStatementExpression statementExpression, String methodName) {\n        ASTName name = statementExpression.getFirstDescendantOfType(ASTName.class);\n        if (name == null || name.getType() == null || !Lock.class.isAssignableFrom(name.getType())) {\n            return false;\n        }\n        Token token = (Token)name.jjtGetLastToken();\n        return methodName.equals(token.image);\n    }\n\n    public static boolean isLockNode(Node node) {\n        if (!(node instanceof ASTStatementExpression)) {\n            return false;\n        }\n        ASTStatementExpression statementExpression = (ASTStatementExpression)node;\n        return isLockStatementExpression(statementExpression);\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/GeneratedCodeUtils.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util;\n\nimport java.util.List;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\nimport net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;\n\n/**\n * @author caikang\n * @date 2017/06/21\n */\npublic class GeneratedCodeUtils {\n    private static final String ANNOTATION_NAME = \"javax.annotation.Generated\";\n\n    private static final String CLASS = \"class\";\n\n    public static boolean isGenerated(ASTCompilationUnit compilationUnit) {\n        List<ASTImportDeclaration> importDeclarationList\n            = compilationUnit.findChildrenOfType(ASTImportDeclaration.class);\n        if (importDeclarationList.isEmpty()) {\n            return false;\n        }\n\n        for (ASTImportDeclaration importDeclaration : importDeclarationList) {\n            if (ANNOTATION_NAME.equals(importDeclaration.getImportedName())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static boolean isGenerated(String content) {\n        int classIndex = content.indexOf(CLASS);\n        if (classIndex <= 1) {\n            return false;\n        }\n        //most of file is not generated\n        String importHeader = content.substring(0, classIndex);\n        return importHeader.contains(ANNOTATION_NAME);\n    }\n}\n\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/NumberConstants.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util;\n\n/**\n * @author caikang\n * @date 2016/12/28\n */\npublic final class NumberConstants {\n    private NumberConstants() {\n        throw new AssertionError(\"com.alibaba.p3c.pmd.lang.java.util.NumberConstants\"\n            + \" instances for you!\");\n    }\n\n    public static final int INTEGER_SIZE_OR_LENGTH_0 = 0;\n    public static final int INTEGER_SIZE_OR_LENGTH_1 = 1;\n    public static final int INTEGER_SIZE_OR_LENGTH_2 = 2;\n    public static final int INTEGER_SIZE_OR_LENGTH_3 = 3;\n\n    public static final int INDEX_0 = 0;\n    public static final int INDEX_1 = 1;\n    public static final int INDEX_2 = 2;\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/PojoUtils.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util;\n\nimport java.util.List;\n\nimport com.alibaba.p3c.pmd.lang.java.util.namelist.NameListConfig;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;\n\n/**\n * POJO Utils\n *\n * @author zenghou.fw\n * @date 2016/11/25\n */\npublic class PojoUtils {\n    private static final List<String> POJO_SUFFIX_SET =\n        NameListConfig.NAME_LIST_SERVICE.getNameList(\"PojoMustOverrideToStringRule\", \"POJO_SUFFIX_SET\");\n\n    private PojoUtils() {\n    }\n\n    public static boolean isPojo(String klass) {\n        if (klass == null) {\n            return false;\n        }\n        for (String suffix : POJO_SUFFIX_SET) {\n            if (klass.endsWith(suffix)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static boolean isPojo(ASTClassOrInterfaceDeclaration node) {\n        return node != null && isPojo(node.getImage());\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/SpiLoader.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util;\n\nimport java.util.ServiceLoader;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.alibaba.p3c.pmd.lang.java.util.namelist.NameListConfig;\n\n/**\n * @author changle.lq\n * @date 2017/04/01\n */\npublic class SpiLoader {\n    private final static ConcurrentHashMap<Class<?>, Object> INSTANCE_CACHE = new ConcurrentHashMap<Class<?>, Object>();\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getInstance(Class<T> classType) {\n        T instance = (T)INSTANCE_CACHE.get(classType);\n\n        if (instance != null) {\n            return instance;\n        }\n        try {\n            instance = ServiceLoader.load(classType, NameListConfig.class.getClassLoader()).iterator().next();\n            if (instance == null) {\n                return null;\n            }\n            INSTANCE_CACHE.putIfAbsent(classType, instance);\n            return instance;\n        } catch (Throwable e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/StringAndCharConstants.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util;\n\n/**\n * @author caikang\n * @date 2017/03/28\n */\npublic final class StringAndCharConstants {\n    private StringAndCharConstants(){\n        throw new AssertionError(\"com.alibaba.p3c.pmd.lang.java.util.StringAndCharConstants\"\n            + \" instances for you!\");\n    }\n\n    public static final char DOT = '.';\n    public static final String DOLLAR = \"$\";\n    public static final String UNDERSCORE = \"_\";\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/VariableUtils.java",
    "content": "package com.alibaba.p3c.pmd.lang.java.util;\n\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode;\n\n/**\n * @author caikang\n * @date 2019/04/22\n */\npublic class VariableUtils {\n    public static String getVariableName(AbstractJavaAccessNode typeNode) {\n        ASTVariableDeclaratorId decl = typeNode.getFirstDescendantOfType(ASTVariableDeclaratorId.class);\n        if (decl != null) {\n            return decl.getImage();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/ViolationUtils.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util;\n\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;\nimport net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;\nimport net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;\nimport net.sourceforge.pmd.lang.rule.AbstractRule;\n\n/**\n * @author caikang\n * @date 2017/01/14\n */\npublic class ViolationUtils {\n    public static void addViolationWithPrecisePosition(AbstractRule rule, Node node, Object data) {\n        addViolationWithPrecisePosition(rule, node, data, null);\n    }\n\n    public static void addViolationWithPrecisePosition(AbstractRule rule, Node node, Object data,\n        String message) {\n        if (node instanceof ASTFieldDeclaration) {\n            ASTVariableDeclaratorId variableDeclaratorId = node.getFirstDescendantOfType(ASTVariableDeclaratorId.class);\n            addViolation(rule, variableDeclaratorId, data, message);\n            return;\n        }\n        if (node instanceof ASTMethodDeclaration) {\n            ASTMethodDeclarator declarator = node.getFirstChildOfType(ASTMethodDeclarator.class);\n            addViolation(rule, declarator, data, message);\n            return;\n        }\n        addViolation(rule, node, data, message);\n    }\n\n    private static void addViolation(AbstractRule rule, Node node, Object data, String message) {\n        if (message == null) {\n            rule.addViolation(data, node);\n        } else {\n            rule.addViolationWithMessage(data, node, message);\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/namelist/NameListConfig.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util.namelist;\n\nimport com.alibaba.p3c.pmd.lang.java.util.SpiLoader;\n\n/**\n * @author changle.lq\n * @date 2017/03/27\n */\npublic class NameListConfig {\n    public static final NameListService NAME_LIST_SERVICE = getNameListService();\n\n    private static NameListService getNameListService() {\n        NameListService instance  = SpiLoader.getInstance(NameListService.class);\n        if (instance == null) {\n            instance = new NameListServiceImpl();\n        }\n        return instance;\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/namelist/NameListService.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util.namelist;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author changle.lq\n * @date 2017/03/23\n */\npublic interface NameListService {\n    /**\n     * get name list\n     * @param className class name\n     * @param name type name\n     * @return  name list\n     */\n    List<String> getNameList(String className,String name);\n\n    /**\n     * get config\n     * @param className class name\n     * @param name type name\n     * @param kClass  type of key\n     * @param vClass  type of value\n     * @param <K> type of key\n     * @param <V> type of value\n     * @return  name list\n     */\n    <K, V> Map<K, V> getNameMap(String className,String name,Class<K> kClass,Class<V> vClass);\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/java/util/namelist/NameListServiceImpl.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.util.namelist;\n\nimport java.io.IOException;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport com.google.gson.Gson;\nimport com.google.gson.reflect.TypeToken;\n\n/**\n * @author changle.lq\n * @date 2017/03/27\n */\npublic class NameListServiceImpl implements NameListService {\n\n    private static final String NAME_LIST_PROPERTY_FILE_NAME = \"namelist.properties\";\n    private static final Properties PROPERTIES = initProperties();\n    private static final String SEPARATOR = \"_\";\n\n    private static Properties initProperties() {\n        LinkedProperties props = new LinkedProperties();\n        ClassLoader classLoader = NameListServiceImpl.class.getClassLoader();\n        try {\n            props.load(classLoader.getResourceAsStream(NAME_LIST_PROPERTY_FILE_NAME));\n        } catch (IOException ex) {\n            throw new IllegalStateException(\"Load namelist.properties fail\", ex);\n        }\n        return props;\n    }\n\n    @Override\n    public List<String> getNameList(String className, String name) {\n        Gson gson = new Gson();\n        return gson.fromJson((String)PROPERTIES.get(className + SEPARATOR + name),\n            new TypeToken<List<String>>() {}.getType());\n    }\n\n    @Override\n    public <K, V> Map<K, V> getNameMap(String className, String name, Class<K> kClass, Class<V> vClass) {\n        Gson gson = new Gson();\n        return gson.fromJson((String)PROPERTIES.get(className + SEPARATOR + name),\n            new TypeToken<Map<K, V>>() {\n            }.getType());\n    }\n\n    private static class LinkedProperties extends Properties {\n        private LinkedHashSet<Object> linkedKeys = new LinkedHashSet<>();\n\n        @Override\n        public Object put(Object key, Object value) {\n            linkedKeys.add(key);\n            return super.put(key, value);\n        }\n\n        public int getSize() {\n            return linkedKeys.size();\n        }\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/java/com/alibaba/p3c/pmd/lang/vm/rule/other/UseQuietReferenceNotationRule.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.vm.rule.other;\n\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport com.alibaba.p3c.pmd.I18nResources;\nimport com.alibaba.p3c.pmd.lang.AbstractXpathRule;\n\nimport net.sourceforge.pmd.RuleContext;\nimport net.sourceforge.pmd.lang.ast.Node;\nimport net.sourceforge.pmd.lang.vm.ast.ASTDirective;\nimport net.sourceforge.pmd.lang.vm.ast.AbstractVmNode;\nimport net.sourceforge.pmd.lang.vm.ast.Token;\nimport net.sourceforge.pmd.lang.vm.ast.VmParserConstants;\n\n/**\n * [Mandatory] Variables must add exclamatory mark when passing to velocity engine from backend, like $!{var}.\n * Note: If attribute is null or does not exist, ${var} will be shown directly on web pages.\n *\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class UseQuietReferenceNotationRule extends AbstractXpathRule {\n    /**\n     * scan file path pattern\n     */\n    private static final Pattern ALLOW_FILE_PATTERN = Pattern.compile(\".*(template|velocity).*\");\n\n    private static final String UT_FILE_NAME = \"n/a\";\n    private static final String MACRO_NAME = \"macro\";\n\n    /**\n     * Check reference between two text nodes. Exclude references scan in method.\n     */\n    private static final String XPATH =\n        \"//Reference[matches(@literal, \\\"^\\\\$[^!]+\\\") and ./preceding-sibling::Text and ./following-sibling::Text]\";\n\n    public UseQuietReferenceNotationRule() {\n        setXPath(XPATH);\n    }\n\n    @Override\n    public void evaluate(Node node, RuleContext ctx) {\n        // Exclude directories other than template and velocity.\n        String sourceCodeFilename = ctx.getSourceCodeFilename();\n\n        // If file path is not n/a（unit test），and does not contain 'template', 'velocity'，then skip it。\n        if (!UT_FILE_NAME.equals(sourceCodeFilename) && !ALLOW_FILE_PATTERN.matcher(sourceCodeFilename).matches()) {\n            return;\n        }\n\n        // Exclude references inside macro.\n        if (checkMacro(node)) {\n            return;\n        }\n\n        super.evaluate(node, ctx);\n    }\n\n    @Override\n    public void addViolation(Object data, Node node, String arg) {\n        String name = getIdentifyName((AbstractVmNode)node);\n        String text = I18nResources.getMessage(\"vm.other.UseQuietReferenceNotationRule.violation.msg\", name);\n        addViolationWithMessage(data, node, text);\n    }\n\n    private String getIdentifyName(AbstractVmNode node) {\n        Token token = node.getFirstToken();\n        StringBuilder sb = new StringBuilder();\n        while (token.kind >= VmParserConstants.IDENTIFIER && token.kind < VmParserConstants.RCURLY) {\n            if (token.kind != VmParserConstants.LCURLY) {\n                sb.append(token.image);\n            }\n            token = token.next;\n        }\n        return sb.toString();\n    }\n\n    /**\n     * Check if reference is inside macro.\n     *\n     * @param node node\n     * @return true/false\n     */\n    private boolean checkMacro(Node node) {\n        List<ASTDirective> directiveParents = node.getParentsOfType(ASTDirective.class);\n\n        for (ASTDirective directiveParent : directiveParents) {\n            if (MACRO_NAME.equals(directiveParent.getDirectiveName())) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/kotlin/com/alibaba/p3c/pmd/lang/java/rule/concurrent/LockShouldWithTryFinallyRule.kt",
    "content": "package com.alibaba.p3c.pmd.lang.java.rule.concurrent\n\nimport com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils.LOCK_INTERRUPTIBLY_NAME\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils.LOCK_NAME\nimport com.alibaba.p3c.pmd.lang.java.rule.util.NodeUtils.UN_LOCK_NAME\nimport net.sourceforge.pmd.lang.java.ast.ASTBlock\nimport net.sourceforge.pmd.lang.java.ast.ASTBlockStatement\nimport net.sourceforge.pmd.lang.java.ast.ASTFinallyStatement\nimport net.sourceforge.pmd.lang.java.ast.ASTName\nimport net.sourceforge.pmd.lang.java.ast.ASTStatementExpression\nimport net.sourceforge.pmd.lang.java.ast.ASTTryStatement\nimport net.sourceforge.pmd.lang.java.ast.AbstractJavaNode\nimport java.util.concurrent.locks.Lock\n\n/**\n * @author caikang\n * @date 2019/09/29\n */\nopen class LockShouldWithTryFinallyRule : AbstractAliRule() {\n\n    override fun visit(node: ASTBlock, data: Any): Any? {\n        checkBlock(node, data)\n        return super.visit(node, data)\n    }\n\n    private fun checkBlock(block: ASTBlock, data: Any) {\n        val statements = block.findChildrenOfType(ASTBlockStatement::class.java)\n        if (statements.isNullOrEmpty()) {\n            return\n        }\n        var lockExpression: ASTStatementExpression? = null\n        for (statement in statements) {\n            if (lockExpression != null) {\n                // check try finally\n                val tryStatement = findNodeByXpath(\n                    statement, XPATH_TRY_STATEMENT,\n                    ASTTryStatement::class.java\n                )\n                if (!checkTryStatement(tryStatement)) {\n                    addLockViolation(data, lockExpression)\n                }\n                lockExpression = null\n                continue\n            }\n            // find lock expression\n            val expression = findNodeByXpath(\n                statement, XPATH_LOCK_STATEMENT,\n                ASTStatementExpression::class.java\n            ) ?: continue\n\n            if (!expression.isLock) {\n                continue\n            }\n            val astName = expression.getFirstDescendantOfType(ASTName::class.java)\n            val lockMethod = astName?.image?.let {\n                it.endsWith(\".$LOCK_NAME\") || it.endsWith(\".$LOCK_INTERRUPTIBLY_NAME\")\n            } ?: false\n            if (!lockMethod) {\n                continue\n            }\n            lockExpression = expression\n        }\n        lockExpression?.let {\n            addLockViolation(data, it)\n        }\n    }\n\n    private fun addLockViolation(data: Any, lockExpression: ASTStatementExpression) {\n        addViolationWithMessage(\n            data, lockExpression,\n            \"java.concurrent.LockShouldWithTryFinallyRule.violation.msg\",\n            arrayOf<Any>(getExpressName(lockExpression))\n        )\n    }\n\n    private fun checkTryStatement(tryStatement: ASTTryStatement?): Boolean {\n        if (tryStatement == null) {\n            return false\n        }\n        val finallyStatement = tryStatement.getFirstChildOfType(ASTFinallyStatement::class.java) ?: return false\n        val statementExpression = findNodeByXpath(\n            finallyStatement,\n            XPATH_UNLOCK_STATEMENT, ASTStatementExpression::class.java\n        ) ?: return false\n\n        if (!statementExpression.isLock) {\n            return false\n        }\n        val astName = statementExpression.getFirstDescendantOfType(ASTName::class.java) ?: return false\n        return astName.image?.endsWith(\".$UN_LOCK_NAME\") ?: false\n    }\n\n    private fun <T> findNodeByXpath(statement: AbstractJavaNode, xpath: String, clazz: Class<T>): T? {\n        val nodes = statement.findChildNodesWithXPath(xpath)\n        if (nodes == null || nodes.isEmpty()) {\n            return null\n        }\n        val node = nodes[0]\n        return if (!clazz.isAssignableFrom(node.javaClass)) {\n            null\n        } else clazz.cast(node)\n    }\n\n    private fun getExpressName(statementExpression: ASTStatementExpression): String {\n        val name = statementExpression.getFirstDescendantOfType(ASTName::class.java)\n        return name.image\n    }\n\n    companion object {\n        private const val XPATH_LOCK_STATEMENT = \"Statement/StatementExpression\"\n        private const val XPATH_UNLOCK_STATEMENT = \"Block/BlockStatement/Statement/StatementExpression\"\n        private const val XPATH_TRY_STATEMENT = \"Statement/TryStatement\"\n    }\n\n    private val ASTStatementExpression?.isLock: Boolean\n        get() = this?.type?.let {\n            Lock::class.java.isAssignableFrom(it)\n        } ?: false\n}\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/META-INF/services/com.alibaba.p3c.pmd.lang.java.util.namelist.NameListService",
    "content": ""
  },
  {
    "path": "p3c-pmd/src/main/resources/messages.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n<properties>\n    <!--naming-->\n    <entry key=\"java.naming.AbstractClassShouldStartWithAbstractNamingRule.violation.msg\">\n        <![CDATA[抽象类【%s】命名应以Abstract或Base开头]]>\n    </entry>\n    <entry key=\"java.naming.ArrayNamingShouldHaveBracketRule.violation.msg\">\n        <![CDATA[数组变量【%s】中括号位置错误]]>\n    </entry>\n    <entry key=\"java.naming.AvoidStartWithDollarAndUnderLineNamingRule.violation.msg\">\n        <![CDATA[【%s】命名不能以_或$开始]]>\n    </entry>\n    <entry key=\"java.naming.BooleanPropertyShouldNotStartWithIsRule.violation.msg\">\n        <![CDATA[布尔字段【%s】不要加is前缀]]>\n    </entry>\n    <entry key=\"java.naming.ClassNamingShouldBeCamelRule.violation.msg\">\n        <![CDATA[【%s】不符合UpperCamelCase命名风格]]>\n    </entry>\n    <entry key=\"java.naming.ConstantFieldShouldBeUpperCaseRule.violation.msg\">\n        <![CDATA[常量【%s】命名应全部大写并以下划线分隔]]>\n    </entry>\n    <entry key=\"java.naming.ExceptionClassShouldEndWithExceptionRule.violation.msg\">\n        <![CDATA[【%s】命名应以Exception结尾]]>\n    </entry>\n    <entry key=\"java.naming.LowerCamelCaseVariableNamingRule.violation.msg.method\">\n        <![CDATA[方法名【%s】不符合lowerCamelCase命名风格]]>\n    </entry>\n    <entry key=\"java.naming.LowerCamelCaseVariableNamingRule.violation.msg.variable\">\n        <![CDATA[变量名【%s】不符合lowerCamelCase命名风格]]>\n    </entry>\n    <entry key=\"java.naming.PackageNamingRule.violation.msg\">\n        <![CDATA[包名【%s】应全部为小写字母和数字组成]]>\n    </entry>\n    <entry key=\"java.naming.ServiceOrDaoClassShouldEndWithImplRule.violation.msg\">\n        <![CDATA[类名【%s】应以Impl结尾]]>\n    </entry>\n    <entry key=\"java.naming.TestClassShouldEndWithTestNamingRule.violation.msg\">\n        <![CDATA[测试类【%s】命名应以Test结尾]]>\n    </entry>\n    <entry key=\"java.naming.IbatisMethodQueryForListRule.violation.msg\">\n        <![CDATA[iBATIS自带的com.ibatis.sqlmap.client.SqlMapClient.queryForList(String statementName,int start,int size)不推荐使用]]>\n    </entry>\n    <entry key=\"java.exception.AvoidReturnInFinallyRule.rule.msg\">\n        <![CDATA[不能在finally块中使用return，finally块中的return返回后方法结束执行，不会再执行try块中的return语句。]]>\n    </entry>\n    <entry key=\"java.exception.AvoidReturnInFinallyRule.violation.msg\">\n        <![CDATA[请不要在finally中使用return]]>\n    </entry>\n\n    <entry key=\"java.exception.MethodReturnWrapperTypeRule.violation.msg\">\n        <![CDATA[返回类型为基本数据类型【%s】，return包装数据类型的对象【%s】时，自动拆箱有可能产生NPE]]>\n    </entry>\n\n    <entry key=\"java.exception.MethodReturnWrapperTypeRule.rule.msg\">\n        <![CDATA[返回类型为基本数据类型，return包装数据类型的对象时，自动拆箱有可能产生NPE]]>\n    </entry>\n\n    <entry key=\"java.exception.TransactionMustHaveRollbackRule.violation.msg.simple\">\n        <![CDATA[注解【Transactional】需要设置rollbackFor属性。]]>\n    </entry>\n    <entry key=\"java.exception.TransactionMustHaveRollbackRule.violation.msg\">\n        <![CDATA[方法【%s】需要在Transactional注解指定rollbackFor或者在方法中显式的rollback。]]>\n    </entry>\n    <entry key=\"java.exception.TransactionMustHaveRollbackRule.rule.msg\">\n        <![CDATA[事务场景中，抛出异常被catch后，如果需要回滚，一定要手动回滚事务。]]>\n    </entry>\n\n    <entry key=\"java.naming.IbatisMethodQueryForListRule.rule.msg\">\n        <![CDATA[iBATIS自带的queryForList(String statementName,int start,int size)不推荐使用]]>\n    </entry>\n    <entry key=\"java.naming.ClassNamingShouldBeCamelRule.rule.msg\">\n        <![CDATA[类名使用UpperCamelCase风格，必须遵从驼峰形式，但以下情形例外：（领域模型的相关命名）DO / BO / DTO / VO / DAO]]>\n    </entry>\n    <entry key=\"java.naming.AbstractClassShouldStartWithAbstractNamingRule.rule.msg\">\n        <![CDATA[抽象类命名使用Abstract或Base开头]]>\n    </entry>\n    <entry key=\"java.naming.ExceptionClassShouldEndWithExceptionRule.rule.msg\">\n        <![CDATA[异常类命名使用Exception结尾]]>\n    </entry>\n    <entry key=\"java.naming.TestClassShouldEndWithTestNamingRule.rule.msg\">\n        <![CDATA[测试类命名以它要测试的类的名称开始，以Test结尾]]>\n    </entry>\n    <entry key=\"java.naming.LowerCamelCaseVariableNamingRule.rule.msg\">\n        <![CDATA[方法名、参数名、成员变量、局部变量都统一使用lowerCamelCase，必须遵从驼峰形式]]>\n    </entry>\n    <entry key=\"java.naming.AvoidStartWithDollarAndUnderLineNamingRule.rule.msg\">\n        <![CDATA[所有编程相关的命名均不能以下划线或美元符号开始]]>\n    </entry>\n    <entry key=\"java.naming.ConstantFieldShouldBeUpperCaseRule.rule.msg\">\n        <![CDATA[常量命名应该全部大写，单词间用下划线隔开，力求语义表达完整清楚，不要嫌名字长]]>\n    </entry>\n    <entry key=\"java.naming.ServiceOrDaoClassShouldEndWithImplRule.rule.msg\">\n        <![CDATA[对于Service和DAO类，基于SOA的理念，暴露出来的服务一定是接口，内部的实现类用Impl的后缀与接口区别]]>\n    </entry>\n    <entry key=\"java.naming.PackageNamingRule.rule.msg\">\n        <![CDATA[包名统一使用小写，点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用单数形式，但是类名如果有复数含义，类名可以使用复数形式]]>\n    </entry>\n    <entry key=\"java.naming.BooleanPropertyShouldNotStartWithIsRule.rule.msg\">\n        <![CDATA[POJO类中的任何布尔类型的变量，都不要加is，否则部分框架解析会引起序列化错误]]>\n    </entry>\n    <entry key=\"java.naming.ArrayNamingShouldHaveBracketRule.rule.msg\">\n        <![CDATA[中括号是数组类型的一部分，数组定义如下：String[] args]]>\n    </entry>\n\n    <entry key=\"java.concurrent.AvoidUseTimerRule.violation.msg\">使用ScheduledExecutorService代替Timer吧</entry>\n    <entry key=\"java.concurrent.AvoidUseTimerRule.rule.msg\">\n        多线程并行处理定时任务时，Timer运行多个TimeTask时，只要其中之一没有捕获抛出的异常，其它任务便会自动终止运行，使用ScheduledExecutorService则没有这个问题。\n    </entry>\n\n    <entry key=\"java.concurrent.AvoidCallStaticSimpleDateFormatRule.violation.msg\">【%s()】可能导致线程安全问题</entry>\n    <entry key=\"java.concurrent.AvoidCallStaticSimpleDateFormatRule.rule.msg\"><![CDATA[SimpleDateFormat 是线程不安全的类，一般不要定义为static变量，如果定义为static，必须加锁，或者使用DateUtils工具类。]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidCallStaticSimpleDateFormatRule.rule.desc\"><![CDATA[\n说明：如果是JDK8的应用，可以使用instant代替Date，LocalDateTime代替Calendar，DateTimeFormatter代替SimpleDateFormat，官方给出的解释：simple beautiful strong immutable thread-safe。\n       ]]></entry>\n\n    <entry key=\"java.concurrent.AvoidConcurrentCompetitionRandomRule.violation.msg.math.random\">\n        <![CDATA[【Math.random()】应避免在多线程并发环境下使用。]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidConcurrentCompetitionRandomRule.violation.msg.random\">\n        <![CDATA[不要在多线程并发环境下使用同一个Random对象【%s】。]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidConcurrentCompetitionRandomRule.rule.msg\">\n        <![CDATA[避免Random实例被多线程使用，虽然共享该实例是线程安全的，但会因竞争同一seed 导致的性能下降。说明：Random实例包括java.util.Random 的实例或者 Math.random()的方式。]]>\n    </entry>\n\n    <entry key=\"java.concurrent.AvoidManuallyCreateThreadRule.violation.msg\">\n        <![CDATA[不要显式创建线程，请使用线程池。]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidManuallyCreateThreadRule.rule.msg\">\n        <![CDATA[线程资源必须通过线程池提供，不允许在应用中自行显式创建线程。]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidManuallyCreateThreadRule.rule.desc\">\n        <![CDATA[\n说明：使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销，解决资源不足的问题。如果不使用线程池，有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。\n       ]]>\n    </entry>\n\n    <entry key=\"java.concurrent.CountDownShouldInFinallyRule.violation.msg\">\n        <![CDATA[【%s()】应该在finally块中调用。]]>\n    </entry>\n    <entry key=\"java.concurrent.CountDownShouldInFinallyRule.rule.msg\">\n        <![CDATA[使用CountDownLatch进行异步转同步操作，每个线程退出前必须调用countDown方法，线程执行代码注意catch异常，确保countDown方法可以执行，避免主线程无法执行至await方法，直到超时才返回结果。]]>\n    </entry>\n    <entry key=\"java.concurrent.CountDownShouldInFinallyRule.rule.desc\">\n        <![CDATA[说明：注意，子线程抛出异常堆栈，不能在主线程try-catch到。]]>\n    </entry>\n\n    <entry key=\"java.concurrent.ThreadLocalShouldRemoveRule.violation.msg\">\n        <![CDATA[ThreadLocal字段【%s】应该至少调用一次remove()方法。]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadLocalShouldRemoveRule.rule.msg\">\n        <![CDATA[必须回收自定义的ThreadLocal变量，尤其在线程池场景下，线程经常会被复用，如果不清理自定义的 ThreadLocal变量，可能会影响后续业务逻辑和造成内存泄露等问题。尽量在代理中使用try-finally块进行回收。]]>\n    </entry>\n\n    <entry key=\"java.concurrent.ThreadPoolCreationRule.violation.msg\">\n        <![CDATA[手动创建线程池，效果会更好哦。]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadPoolCreationRule.rule.msg\">\n        <![CDATA[线程池不允许使用Executors去创建，而是通过ThreadPoolExecutor的方式，这样的处理方式让写的同学更加明确线程池的运行规则，规避资源耗尽的风险。]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadPoolCreationRule.rule.desc\">\n        <![CDATA[\n说明：Executors返回的线程池对象的弊端如下：\n1）FixedThreadPool和SingleThreadPool:\n  允许的请求队列长度为Integer.MAX_VALUE，可能会堆积大量的请求，从而导致OOM。\n2）CachedThreadPool:\n  允许的创建线程数量为Integer.MAX_VALUE，可能会创建大量的线程，从而导致OOM。]]>\n    </entry>\n\n    <entry key=\"java.concurrent.ThreadShouldSetNameRule.violation.msg.ThreadPoolExecutor\">\n        <![CDATA[要使用带有ThreadFactory参数的ThreadPoolExecutor构造方法哦，这样你就可以方便的设置线程名字啦。]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadShouldSetNameRule.violation.msg.ScheduledThreadPoolExecutor\">\n        <![CDATA[要使用带有ThreadFactory参数的ScheduledThreadPoolExecutor构造方法哦，这样你就可以方便的设置线程名字啦。]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadShouldSetNameRule.rule.msg\">\n        <![CDATA[创建线程或线程池时请指定有意义的线程名称，方便出错时回溯。创建线程池的时候请使用带ThreadFactory的构造函数，并且提供自定义ThreadFactory实现或者使用第三方实现。]]>\n    </entry>\n    <entry key=\"java.concurrent.LockShouldWithTryFinallyRule.violation.msg\">\n        <![CDATA[锁【%s】必须紧跟try代码块，且unlock要放到finally第一行。]]>\n    </entry>\n    <entry key=\"java.concurrent.LockShouldWithTryFinallyRule.rule.msg\">\n        <![CDATA[在使用阻塞等待获取锁的方式中，必须在try代码块之外，并且在加锁方法与try代码块之间没有任何可能抛出异常的方法调用，避免加锁成功后，在finally中无法解锁。\n说明一：如果在lock方法与try代码块之间的方法调用抛出异常，那么无法解锁，造成其它线程无法成功获取锁。\n说明二：如果lock方法在try代码块之内，可能由于其它方法抛出异常，导致在finally代码块中，unlock对未加锁的对象解锁，它会调用AQS的tryRelease方法（取决于具体实现类），抛出IllegalMonitorStateException异常。\n说明三：在Lock对象的lock方法实现中可能抛出unchecked异常，产生的后果与说明二相同。]]>\n    </entry>\n\n    <!-- flowcontrol -->\n    <entry key=\"java.flowcontrol.SwitchStatementRule.violation.nodefault\">\n        <![CDATA[switch块缺少default语句]]>\n    </entry>\n    <entry key=\"java.flowcontrol.SwitchStatementRule.violation.notermination\">\n        <![CDATA[switch中每个case需要通过break/return等来终止]]>\n    </entry>\n    <entry key=\"java.flowcontrol.SwitchStatementRule.rule.msg\">\n        <![CDATA[在一个switch块内，每个case要么通过break/return等来终止，要么注释说明程序将继续执行到哪一个case为止；在一个switch块内，都必须包含一个default语句并且放在最后，即使它什么代码也没有。]]>\n    </entry>\n\n    <entry key=\"java.flowcontrol.NeedBraceRule.violation.msg\">\n        <![CDATA[%s语句缺少大括号]]>\n    </entry>\n    <entry key=\"java.flowcontrol.NeedBraceRule.rule.msg\">\n        <![CDATA[在if/else/for/while/do语句中必须使用大括号，即使只有一行代码，避免使用下面的形式：if (condition) statements;]]>\n    </entry>\n\n    <entry key=\"java.flowcontrol.AvoidComplexConditionRule.violation.msg\">\n        <![CDATA[请不要在条件中使用复杂的表达式。]]>\n    </entry>\n    <entry key=\"java.flowcontrol.AvoidComplexConditionRule.rule.msg\">\n        <![CDATA[除常用方法（如getXxx/isXxx）等外，不要在条件判断中执行复杂的语句，将复杂逻辑判断的结果赋值给一个有意义的布尔变量，以提高可读性。]]>\n    </entry>\n    <entry key=\"java.flowcontrol.AvoidComplexConditionRule.rule.desc\">\n        <![CDATA[说明：很多if语句内的逻辑相当复杂，阅读者需要分析条件表达式的最终结果，才能明确什么样的条件执行什么样的语句，那么，如果阅读者分析逻辑表达式错误呢？]]>\n    </entry>\n\n    <entry key=\"java.flowcontrol.AvoidNegationOperatorRule.violation.msg\">\n        <![CDATA[\"!\"运算符不利于快速理解。]]>\n    </entry>\n    <entry key=\"java.flowcontrol.AvoidNegationOperatorRule.rule.msg\">\n        <![CDATA[避免采用取反逻辑运算符。]]>\n    </entry>\n    <entry key=\"java.flowcontrol.AvoidNegationOperatorRule.rule.desc\">\n        <![CDATA[说明: 取反逻辑不利于快速理解，并且取反逻辑写法必然存在对应的正向逻辑写法。]]>\n    </entry>\n\n    <!-- set -->\n    <entry key=\"java.set.ClassCastExceptionWithSubListToArrayListRule.violation.msg\">\n        <![CDATA[【%s】的结果不可强转成ArrayList]]>\n    </entry>\n    <entry key=\"java.set.ClassCastExceptionWithSubListToArrayListRule.rule.msg\">\n        <![CDATA[ ArrayList的subList结果不可强转成ArrayList，否则会抛出ClassCastException异常。 ]]>\n    </entry>\n    <entry key=\"java.set.ClassCastExceptionWithSubListToArrayListRule.rule.msg.desc\">\n        <![CDATA[ 说明:禁止强转，如果需要用到集合特性方法，请新建一个集合，然后置入sublist,new 集合(sublist结果)。 ]]>\n    </entry>\n    <entry key=\"java.set.ClassCastExceptionWithToArrayRule.violation.msg\">\n        <![CDATA[【%s】应使用大小一致类型一致的数组参数]]>\n    </entry>\n    <entry key=\"java.set.ClassCastExceptionWithToArrayRule.rule.msg\">\n        <![CDATA[使用集合转数组的方法，必须使用集合的toArray(T[] array)，传入的是类型完全一样的数组，大小就是list.size()]]>\n    </entry>\n    <entry key=\"java.set.CollectionInitShouldAssignCapacityRule.violation.msg\">\n        <![CDATA[【%s】初始化时，尽量指定初始值大小]]>\n    </entry>\n    <entry key=\"java.set.CollectionInitShouldAssignCapacityRule.rule.msg\">\n        <![CDATA[集合初始化时，指定集合初始值大小。]]>\n    </entry>\n    <entry key=\"java.set.CollectionInitShouldAssignCapacityRule.rule.msg.desc\">\n        <![CDATA[说明：HashMap使用如下构造方法进行初始化，如果暂时无法确定集合大小，那么指定默认值（16）即可。]]>\n    </entry>\n    <entry key=\"java.set.ConcurrentExceptionWithModifyOriginSubListRule.violation.msg\">\n        <![CDATA[【%s】在这里可能会导致ConcurrentModificationException]]>\n    </entry>\n    <entry key=\"java.set.ConcurrentExceptionWithModifyOriginSubListRule.rule.msg\">\n        <![CDATA[在subList场景中，高度注意对原列表的修改，会导致子列表的遍历、增加、删除均产生ConcurrentModificationException异常。]]>\n    </entry>\n    <entry key=\"java.set.DontModifyInForeachCircleRule.violation.msg\">\n        <![CDATA[ 不要在遍历中使用【%s】]]>\n    </entry>\n    <entry key=\"java.set.DontModifyInForeachCircleRule.rule.msg\">\n        <![CDATA[ 不要在foreach循环里进行元素的remove/add操作，remove元素请使用Iterator方式。]]>\n    </entry>\n    <entry key=\"java.set.UnsupportedExceptionWithModifyAsListRule.violation.msg\">\n        <![CDATA[ 这里使用【%s】可能会导致UnsupportedOperationException ]]>\n    </entry>\n    <entry key=\"java.set.UnsupportedExceptionWithModifyAsListRule.rule.msg\">\n        <![CDATA[ 使用工具类Arrays.asList()把数组转换成集合时，不能使用其修改集合相关的方法，它的add/remove/clear方法会抛出UnsupportedOperationException异常。 ]]>\n    </entry>\n    <!-- constant -->\n    <entry key=\"java.constant.UndefineMagicConstantRule.violation.msg\">\n        <![CDATA[ 魔法值【%s】]]>\n    </entry>\n    <entry key=\"java.constant.UndefineMagicConstantRule.rule.msg\">\n        <![CDATA[ 不允许任何魔法值（即未经定义的常量）直接出现在代码中。]]>\n    </entry>\n    <entry key=\"java.constant.UpperEllRule.violation.msg\">\n        <![CDATA[【%s】应使用大写L ]]>\n    </entry>\n    <entry key=\"java.constant.UpperEllRule.rule.msg\">\n        <![CDATA[ long或者Long初始赋值时，必须使用大写的L，不能是小写的l，小写容易跟数字1混淆，造成误解。]]>\n    </entry>\n\n\n    <!-- oop -->\n    <entry key=\"java.oop.EqualsAvoidNullRule.violation.msg\">\n        <![CDATA[【%s】应该作为equals的参数，而不是调用方]]>\n    </entry>\n    <entry key=\"java.oop.EqualsAvoidNullRule.rule.msg\">\n        <![CDATA[Object的equals方法容易抛空指针异常，应使用常量或确定有值的对象来调用equals。]]>\n    </entry>\n\n    <entry key=\"java.oop.WrapperTypeEqualityRule.violation.msg\">\n        <![CDATA[应使用equals方法代替==]]>\n    </entry>\n    <entry key=\"java.oop.WrapperTypeEqualityRule.rule.msg\">\n        <![CDATA[所有的包装类对象之间值的比较，全部使用equals方法比较。]]>\n    </entry>\n    <entry key=\"java.oop.WrapperTypeEqualityRule.rule.desc\">\n        <![CDATA[说明：对于Integer var=?在-128至127之间的赋值，Integer对象是在IntegerCache.cache产生，会复用已有对象，这个区间内的Integer值可以直接使用==进行判断，但是这个区间之外的所有数据，都会在堆上产生，并不会复用已有对象，这是一个大坑，推荐使用equals方法进行判断。]]>\n    </entry>\n\n    <entry key=\"java.oop.PojoMustUsePrimitiveFieldRule.violation.msg\">\n        <![CDATA[字段【%s】应使用包装类型]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustUsePrimitiveFieldRule.rule.msg\">\n        <![CDATA[\n关于基本数据类型与包装数据类型的使用标准如下：\n 1） 所有的POJO类属性必须使用包装数据类型。\n 2） RPC方法的返回值和参数必须使用包装数据类型。\n 3） 所有的局部变量推荐使用基本数据类型。\n        ]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustUsePrimitiveFieldRule.rule.msg.desc\">\n        <![CDATA[说明：POJO类属性没有初值是提醒使用者在需要使用时，必须自己显式地进行赋值，任何NPE问题，或者入库检查，都由使用者来保证。]]>\n    </entry>\n\n    <entry key=\"java.oop.PojoNoDefaultValueRule.violation.msg\">\n        <![CDATA[字段【%s】不应该加默认值]]>\n    </entry>\n    <entry key=\"java.oop.PojoNoDefaultValueRule.rule.msg\">\n        <![CDATA[定义DO/DTO/VO等POJO类时，不要加任何属性默认值。]]>\n    </entry>\n\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.violation.msg.notostring\">\n        <![CDATA[【%s】没有写toString方法]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.violation.msg.usesuper\">\n        <![CDATA[注意在前面加一下super.toString]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.rule.msg\">\n        <![CDATA[POJO类必须写toString方法。使用工具类source> generate toString时，如果继承了另一个POJO类，注意在前面加一下super.toString。]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.rule.desc\">\n        <![CDATA[说明：在方法执行抛出异常时，可以直接调用POJO的toString()方法打印其属性值，便于排查问题。]]>\n    </entry>\n\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.violation.msg\">\n        <![CDATA[请不要在循环体内使用\"+\"连接字符串]]>\n    </entry>\n    <entry key=\"java.oop.StringConcatRule.rule.msg\">\n        <![CDATA[循环体内，字符串的联接方式，使用StringBuilder的append方法进行扩展。]]>\n    </entry>\n    <entry key=\"java.oop.StringConcatRule.rule.msg.desc\">\n        <![CDATA[说明：反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象，然后进行append操作，最后通过toString方法返回String对象，造成内存资源浪费。]]>\n    </entry>\n\n    <entry key=\"java.oop.BigDecimalAvoidDoubleConstructorRule.violation.msg\">\n        <![CDATA[使用了new BigDecimal(double)构造函数]]>\n    </entry>\n    <entry key=\"java.oop.BigDecimalAvoidDoubleConstructorRule.rule.msg\">\n        <![CDATA[禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象]]>\n    </entry>\n    <entry key=\"java.oop.BigDecimalAvoidDoubleConstructorRule.rule.msg.desc\">\n        <![CDATA[说明：BigDecimal(double)存在精度损失风险，在精确计算或值比较的场景中可能会导致业务逻辑异常。]]>\n    </entry>\n\n    <!-- comment -->\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.rule.msg\">\n        <![CDATA[类、类属性、类方法的注释必须使用javadoc规范，使用/**内容*/格式，不得使用//xxx方式和/*xxx*/方式。]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.rule.desc\">\n        <![CDATA[\n说明：在IDE编辑窗口中，javadoc方式会提示相关注释，生成javadoc可以正确输出相应注释；在IDE中，工程调用方法时，不进入方法即可悬浮提示方法、参数、返回值的意义，提高阅读效率。\n        ]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.class\">\n        <![CDATA[类【%s】必须使用javadoc形式的注释]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.constructor.default\">\n        <![CDATA[构造方法【%s()】必须使用javadoc形式的注释]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.constructor.parameter\">\n        <![CDATA[构造方法【%s(%s)】必须使用javadoc形式的注释]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.method\">\n        <![CDATA[方法【%s】必须使用javadoc形式的注释]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.field\">\n        <![CDATA[字段【%s】必须使用javadoc形式的注释]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.enum\">\n        <![CDATA[枚举【%s】必须使用javadoc形式的注释]]>\n    </entry>\n\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.rule.msg\">\n        <![CDATA[所有的抽象方法（包括接口中的方法）必须要用javadoc注释、除了返回值、参数、异常说明外，还必须指出该方法做什么事情，实现什么功能。]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.rule.desc\">\n        <![CDATA[\n说明：如有实现和调用注意事项，请一并说明。\n        ]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.abstract\">\n        <![CDATA[抽象方法【%s】必须使用javadoc注释]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.interface\">\n        <![CDATA[接口方法【%s】必须使用javadoc注释]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.desc\">\n        <![CDATA[请详细描述方法【%s】的功能与意图]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.parameter\">\n        <![CDATA[方法【%s】的参数【%s】缺少javadoc注释]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.return\">\n        <![CDATA[方法【%s】的返回值缺少javadoc注释]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.exception\">\n        <![CDATA[方法【%s】的异常【%s】缺少javadoc注释]]>\n    </entry>\n\n\n    <entry key=\"java.comment.AvoidCommentBehindStatementRule.rule.msg\">\n        <![CDATA[方法内部单行注释，在被注释语句上方另起一行，使用//注释。方法内部多行注释使用/* */注释。注意与代码对齐。]]>\n    </entry>\n    <entry key=\"java.comment.AvoidCommentBehindStatementRule.violation.msg\">\n        <![CDATA[请不要使用行尾注释]]>\n    </entry>\n\n    <entry key=\"java.comment.ClassMustHaveAuthorRule.rule.msg\">\n        <![CDATA[所有的类都必须添加创建者信息。]]>\n    </entry>\n    <entry key=\"java.comment.ClassMustHaveAuthorRule.rule.desc\">\n        <![CDATA[\n说明：在设置模板时，注意IDEA的@author为${USER}，而eclipse的@author为${user}，大小写有区别，而日期的设置统一为yyyy/MM/dd的格式。\n        ]]>\n    </entry>\n    <entry key=\"java.comment.ClassMustHaveAuthorRule.violation.msg.comment\">\n        <![CDATA[【%s】缺少包含@author的注释信息]]>\n    </entry>\n    <entry key=\"java.comment.ClassMustHaveAuthorRule.violation.msg.author\">\n        <![CDATA[【%s】注释缺少@author信息]]>\n    </entry>\n\n    <entry key=\"java.comment.EnumConstantsMustHaveCommentRule.rule.msg\">\n        <![CDATA[所有的枚举类型字段必须要有注释，说明每个数据项的用途。]]>\n    </entry>\n    <entry key=\"java.comment.EnumConstantsMustHaveCommentRule.violation.msg\">\n        <![CDATA[枚举【%s】的字段缺少注释信息]]>\n    </entry>\n\n    <entry key=\"java.comment.RemoveCommentedCodeRule.rule.msg\">\n        <![CDATA[及时清理不再使用的代码段或配置信息。]]>\n    </entry>\n    <entry key=\"java.comment.RemoveCommentedCodeRule.rule.desc\">\n        <![CDATA[\n说明：对于垃圾代码或过时配置，坚决清理干净，避免程序过度臃肿，代码冗余。\n        ]]>\n    </entry>\n\n    <!-- java other -->\n    <entry key=\"java.other.AvoidPatternCompileInMethodRule.rule.msg\">\n        <![CDATA[在使用正则表达式时，利用好其预编译功能，可以有效加快正则匹配速度。]]>\n    </entry>\n    <entry key=\"java.other.AvoidPatternCompileInMethodRule.rule.desc\">\n        <![CDATA[\n说明：不要在方法体内定义：Pattern pattern = Pattern.compile(规则);\n        ]]>\n    </entry>\n    <entry key=\"java.other.AvoidPatternCompileInMethodRule.violation.msg\">\n        <![CDATA[变量【%s】应定义为常量或者字段]]>\n    </entry>\n\n    <entry key=\"java.other.AvoidApacheBeanUtilsCopyRule.rule.msg\">\n        <![CDATA[避免用Apache Beanutils进行属性的copy。]]>\n    </entry>\n    <entry key=\"java.other.AvoidApacheBeanUtilsCopyRule.rule.desc\">\n        <![CDATA[\n说明：Apache BeanUtils性能较差，可以使用其他方案比如Spring BeanUtils, Cglib BeanCopier。\n        ]]>\n    </entry>\n\n    <entry key=\"java.other.AvoidNewDateGetTimeRule.rule.msg\">\n        <![CDATA[获取当前毫秒数：System.currentTimeMillis(); 而不是new Date().getTime();]]>\n    </entry>\n    <entry key=\"java.other.AvoidNewDateGetTimeRule.rule.desc\">\n        <![CDATA[\n说明：如果想获取更加精确的纳秒级时间值，用System.nanoTime。在JDK8中，针对统计时间等场景，推荐使用Instant类。\n        ]]>\n    </entry>\n    <entry key=\"java.other.AvoidNewDateGetTimeRule.violation.msg\">\n        <![CDATA[请使用System.currentTimeMillis()代替new Date().getTime()]]>\n    </entry>\n\n    <entry key=\"java.other.AvoidMissUseOfMathRandomRule.rule.msg\">\n        <![CDATA[注意 Math.random() 这个方法返回是double类型，注意取值的范围[0,1)（能够取到零值，注意除零异常），如果想获取整数类型的随机数，不要将x放大10的若干倍然后取整，直接使用Random对象的nextInt或者nextLong方法。]]>\n    </entry>\n\n    <entry key=\"java.other.MethodTooLongRule.rule.msg\">\n        <![CDATA[单个方法的总行数不超过80行。]]>\n    </entry>\n\n    <entry key=\"java.other.MethodTooLongRule.rule.desc\">\n        <![CDATA[\n说明：除注释之外的方法签名、结束右大括号、方法内代码、空行、回车及任何不可见字符的总行数不超过80行。\n        ]]>\n    </entry>\n\n    <entry key=\"java.other.MethodTooLongRule.violation.msg\">\n        <![CDATA[方法【%s】的总行数不要超过80行。]]>\n    </entry>\n\n    <entry key=\"java.other.UseRightCaseForDateFormatRule.rule.msg\">\n        <![CDATA[日期格式化字符串[%s]使用错误，应注意使用小写‘y’表示当天所在的年，大写‘Y’代表week in which year。]]>\n    </entry>\n    <entry key=\"java.other.UseRightCaseForDateFormatRule.rule.desc\">\n        <![CDATA[日期格式化时，yyyy表示当天所在的年，而大写的YYYY代表是week in which year（JDK7之后引入的概念），意思是当天所在的周属于的年份，一周从周日开始，周六结束，只要本周跨年，返回的YYYY就是下一年。]]>\n    </entry>\n\n    <!-- other -->\n    <entry key=\"vm.other.UseQuietReferenceNotationRule.rule.msg\">\n        <![CDATA[后台输送给页面的变量必须加感叹号，${var}——中间加感叹号！。]]>\n    </entry>\n    <entry key=\"vm.other.UseQuietReferenceNotationRule.rule.desc\">\n        <![CDATA[\n说明：如果var=null或者不存在，那么${var}会直接显示在页面上。\n        ]]>\n    </entry>\n    <entry key=\"vm.other.UseQuietReferenceNotationRule.violation.msg\">\n        <![CDATA[变量【%s】使用的时候应在$后加感叹号]]>\n    </entry>\n\n    <entry key=\"java.other.AvoidDoubleOrFloatEqualCompareRule.rule.msg\">\n        <![CDATA[浮点数之间的等值判断，基本数据类型不能用==来比较，包装数据类型不能用equals来判断]]>\n    </entry>\n    <entry key=\"java.other.AvoidDoubleOrFloatEqualCompareRule.rule.desc\">\n        <![CDATA[\n浮点数采用“尾数+阶码”的编码方式，类似于科学计数法的“有效数字+指数”的表示方式。二进制无法精确表示大部分的十进制小数，具体原理参考《码出高效》\n改进方式:\n1）指定一个误差范围，两个浮点数的差值在此范围之内，则认为是相等的\n    float a = 1.0f - 0.9f;\n    float b = 0.9f - 0.8f;\n    float diff = 1e-6f;\n\n    if (Math.abs(a - b) < diff) {\n        System.out.println(\"true\");\n    }\n2) 使用BigDecimal来定义值，再进行浮点数的运算操作\n    BigDecimal a = new BigDecimal(\"1.0\");\n    BigDecimal b = new BigDecimal(\"0.9\");\n    BigDecimal c = new BigDecimal(\"0.8\");\n\n    BigDecimal x = a.subtract(b);\n    BigDecimal y = b.subtract(c);\n\n    if (x.equals(y)) {\n        System.out.println(\"true\");\n    }\n        ]]>\n    </entry>\n    <entry key=\"java.other.AvoidDoubleOrFloatEqualCompareRule.rule.msg\">\n        <![CDATA[浮点数之间的等值判断，基本数据类型不能用==来比较，包装数据类型不能用equals来判断。]]>\n    </entry>\n\n</properties>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/messages_en.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n<properties>\n    <entry key=\"java.naming.AbstractClassShouldStartWithAbstractNamingRule.violation.msg\">\n        <![CDATA[Abstract class [%s] names must start with Abstract or Base]]>\n    </entry>\n    <entry key=\"java.naming.ArrayNamingShouldHaveBracketRule.violation.msg\">\n        <![CDATA[An array variable [%s] brackets position error]]>\n    </entry>\n    <entry key=\"java.naming.AvoidStartWithDollarAndUnderLineNamingRule.violation.msg\">\n        <![CDATA[[%s] should not start or end with an underline or a dollar sign]]>\n    </entry>\n    <entry key=\"java.naming.BooleanPropertyShouldNotStartWithIsRule.violation.msg\">\n        <![CDATA[Boolean variable [%s] should not add prefix is]]>\n    </entry>\n    <entry key=\"java.naming.ClassNamingShouldBeCamelRule.violation.msg\">\n        <![CDATA[[%s] not conform to the UpperCamelCase]]>\n    </entry>\n    <entry key=\"java.naming.ConstantFieldShouldBeUpperCaseRule.violation.msg\">\n        <![CDATA[Constant [%s] should be written in upper characters separated by underscores]]>\n    </entry>\n    <entry key=\"java.naming.ExceptionClassShouldEndWithExceptionRule.violation.msg\">\n        <![CDATA[[%s] must be ended with Exception]]>\n    </entry>\n    <entry key=\"java.naming.LowerCamelCaseVariableNamingRule.violation.msg.method\">\n        <![CDATA[method [%s] not conform to the lowerCamelCase]]>\n    </entry>\n    <entry key=\"java.naming.LowerCamelCaseVariableNamingRule.violation.msg.variable\">\n        <![CDATA[variable [%s] not conform to the lowerCamelCase]]>\n    </entry>\n    <entry key=\"java.naming.PackageNamingRule.violation.msg\">\n        <![CDATA[Package [%s] should be named in lowercase characters]]>\n    </entry>\n    <entry key=\"java.naming.ServiceOrDaoClassShouldEndWithImplRule.violation.msg\">\n        <![CDATA[class [%s] should be ended with Impl]]>\n    </entry>\n    <entry key=\"java.naming.TestClassShouldEndWithTestNamingRule.violation.msg\">\n        <![CDATA[Test cases [%s] should be ended with Test]]>\n    </entry>\n    <entry key=\"java.naming.IbatisMethodQueryForListRule.violation.msg\">\n        <![CDATA[iBatis built in com.ibatis.sqlmap.client.SqlMapClient.queryForList(String statementName,int start,int size) is not recommended]]>\n    </entry>\n\n    <entry key=\"java.exception.AvoidReturnInFinallyRule.rule.msg\">\n        <![CDATA[Never use return within a finally block. A return statement in a finally block will cause exceptions or result in a discarded return value in the try-catch block.]]>\n    </entry>\n\n    <entry key=\"java.exception.AvoidReturnInFinallyRule.violation.msg\">\n        <![CDATA[return in finally is prohibited]]>\n    </entry>\n\n    <entry key=\"java.exception.MethodReturnWrapperTypeRule.violation.msg\">\n        <![CDATA[the return type is primitive[%s], return a value of wrapper class[%s], may cause NullPointerException]]>\n    </entry>\n\n    <entry key=\"java.exception.MethodReturnWrapperTypeRule.rule.msg\">\n        <![CDATA[If the return type is primitive, return a value of wrapper class may cause NullPointerException]]>\n    </entry>\n\n    <entry key=\"java.exception.TransactionMustHaveRollbackRule.violation.msg.simple\">\n        <![CDATA[Attribute rollbackFor of annotation Transactional must be set.]]>\n    </entry>\n    <entry key=\"java.exception.TransactionMustHaveRollbackRule.violation.msg\">\n        <![CDATA[Annotation of Method [%s] should set value of rollbackFor attribute or call rollback() method explicitly.]]>\n    </entry>\n    <entry key=\"java.exception.TransactionMustHaveRollbackRule.rule.msg\">\n        <![CDATA[Make sure to invoke the rollback if a method throws an Exception.]]>\n    </entry>\n\n\n    <entry key=\"java.naming.IbatisMethodQueryForListRule.rule.msg\">\n        <![CDATA[iBatis built in queryForList(String statementName, int start, int size) is not recommended]]>\n    </entry>\n    <entry key=\"java.naming.ClassNamingShouldBeCamelRule.rule.msg\">\n        <![CDATA[Class names should be nouns in UpperCamelCase except domain models: DO, BO, DTO, VO, DAO, etc]]>\n    </entry>\n    <entry key=\"java.naming.AbstractClassShouldStartWithAbstractNamingRule.rule.msg\">\n        <![CDATA[Abstract class names must start with Abstract or Base]]>\n    </entry>\n    <entry key=\"java.naming.ExceptionClassShouldEndWithExceptionRule.rule.msg\">\n        <![CDATA[Exception class names must be ended with Exception]]>\n    </entry>\n    <entry key=\"java.naming.TestClassShouldEndWithTestNamingRule.rule.msg\">\n        <![CDATA[Test cases shall be started with the class names to be tested and ended with Test]]>\n    </entry>\n    <entry key=\"java.naming.LowerCamelCaseVariableNamingRule.rule.msg\">\n        <![CDATA[Method names, parameter names, member variable names, and local variable names should be written in lowerCamelCase]]>\n    </entry>\n    <entry key=\"java.naming.AvoidStartWithDollarAndUnderLineNamingRule.rule.msg\">\n        <![CDATA[All names should not start or end with an underline or a dollar sign]]>\n    </entry>\n    <entry key=\"java.naming.ConstantFieldShouldBeUpperCaseRule.rule.msg\">\n        <![CDATA[Constant variable names should be written in upper characters separated by underscores. These names should be semantically complete and clear]]>\n    </entry>\n    <entry key=\"java.naming.ServiceOrDaoClassShouldEndWithImplRule.rule.msg\">\n        <![CDATA[All Service and DAO classes must be interface based on SOA principle. Implementation class names should be ended with Impl]]>\n    </entry>\n    <entry key=\"java.naming.PackageNamingRule.rule.msg\">\n        <![CDATA[All Service and DAO classes must be interface based on SOA principle. Implementation class names]]>\n    </entry>\n    <entry key=\"java.naming.BooleanPropertyShouldNotStartWithIsRule.rule.msg\">\n        <![CDATA[Do not add 'is' as prefix while defining Boolean variable, since it may cause a serialization exception in some Java Frameworks]]>\n    </entry>\n    <entry key=\"java.naming.ArrayNamingShouldHaveBracketRule.rule.msg\">\n        <![CDATA[Brackets are a part of an Array type. The definition could be: String[] args]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidUseTimerRule.violation.msg\">Use ScheduledExecutorService instead.</entry>\n    <entry key=\"java.concurrent.AvoidUseTimerRule.rule.msg\">\n        <![CDATA[Run multiple TimeTask by using ScheduledExecutorService rather than Timer because Timer will kill all running threads in case of failing to catch exceptions.]]>\n    </entry>\n\n\n    <entry key=\"java.concurrent.AvoidCallStaticSimpleDateFormatRule.violation.msg\">[%s()] may cause thread-safety issues.\n    </entry>\n    <entry key=\"java.concurrent.AvoidCallStaticSimpleDateFormatRule.rule.msg\">\n        <![CDATA[SimpleDataFormat is unsafe, do not define it as a static variable. If have to, lock or DateUtils class must be used.]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidCallStaticSimpleDateFormatRule.rule.desc\"><![CDATA[\nNote: In JDK8, Instant can be used to replace Date, Calendar is replaced by LocalDateTime, SimpleDateFormat is replaced by DateTimeFormatter.\n       ]]></entry>\n\n    <entry key=\"java.concurrent.AvoidConcurrentCompetitionRandomRule.violation.msg.math.random\">\n        <![CDATA[Avoid using [Math.random()] by multiple threads.]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidConcurrentCompetitionRandomRule.violation.msg.random\">\n        <![CDATA[Avoid using Random instance [%s] by multiple threads.]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidConcurrentCompetitionRandomRule.rule.msg\">\n        <![CDATA[Avoid using Random instance by multiple threads. Although it is safe to share this instance, competition on the same seed will damage performance. Note: Random instance includes instances of java.util.Random and Math.random().]]>\n    </entry>\n\n    <entry key=\"java.concurrent.AvoidManuallyCreateThreadRule.violation.msg\">\n        <![CDATA[Explicitly creating threads is not allowed, use thread pool instead.]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidManuallyCreateThreadRule.rule.msg\">\n        <![CDATA[Threads should be provided by thread pools. Explicitly creating threads is not allowed.]]>\n    </entry>\n    <entry key=\"java.concurrent.AvoidManuallyCreateThreadRule.rule.desc\">\n        <![CDATA[Note: Using thread pool can reduce the time of creating and destroying thread and save system resource. If we do not use thread pools, lots of similar threads will be created which lead to \"running out of memory\" or over-switching problems.]]>\n    </entry>\n\n    <entry key=\"java.concurrent.CountDownShouldInFinallyRule.violation.msg\">\n        <![CDATA[[%s()] should be called in finally block.]]>\n    </entry>\n    <entry key=\"java.concurrent.CountDownShouldInFinallyRule.rule.msg\">\n        <![CDATA[When using CountDownLatch to convert asynchronous operations to synchronous ones,each thread must call countdown method before quitting. Make sure to catch any exception during thread running, to let countdown method be executed. If main thread cannot reach await method, program will return until timeout.]]>\n    </entry>\n    <entry key=\"java.concurrent.CountDownShouldInFinallyRule.rule.desc\">\n        <![CDATA[Note: Be careful, exception thrown by sub-thread cannot be caught by main thread.]]>\n    </entry>\n\n    <entry key=\"java.concurrent.ThreadLocalShouldRemoveRule.violation.msg\">\n        <![CDATA[Field [%s] of type 'ThreadLocal' must call remove() method at least one times.]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadLocalShouldRemoveRule.rule.msg\">\n        <![CDATA[Customized ThreadLocal variables must be recycled,especially when using thread pools in which threads are often reused. Otherwise, it may affect subsequent business logic and cause unexpected problems such as memory leak.]]>\n    </entry>\n\n    <entry key=\"java.concurrent.ThreadPoolCreationRule.violation.msg\">\n        <![CDATA[Manually create thread pool is better.]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadPoolCreationRule.rule.msg\">\n        <![CDATA[A thread pool should be created by ThreadPoolExecutor rather than Executors. These would make the parameters of the thread pool understandable. It would also reduce the risk of running out of system resource.]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadPoolCreationRule.rule.desc\">\n        <![CDATA[\nNote: Below are the problems created by usage of Executors for thread pool creation:\n1) FixedThreadPool and SingleThreadPool:\n Maximum request queue size Integer.MAX_VALUE. A large number of requests might cause OOM.\n2) CachedThreadPool:\n The number of threads which are allowed to be created is Integer.MAX_VALUE. Creating too many threads might lead to OOM.]]>\n    </entry>\n\n    <entry key=\"java.concurrent.ThreadShouldSetNameRule.violation.msg.ThreadPoolExecutor\">\n        <![CDATA[Use ThreadPoolExecutor's constructor with parameter of type ThreadFactory to set a thread name.]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadShouldSetNameRule.violation.msg.ScheduledThreadPoolExecutor\">\n        <![CDATA[Use ScheduledThreadPoolExecutor's constructor with parameter of type ThreadFactory to set a thread name.]]>\n    </entry>\n    <entry key=\"java.concurrent.ThreadShouldSetNameRule.rule.msg\">\n        <![CDATA[A meaningful thread name is helpful to trace the error information,so assign a name when creating threads or thread pools.]]>\n    </entry>\n    <entry key=\"java.concurrent.LockShouldWithTryFinallyRule.violation.msg\">\n        <![CDATA[Lock operation [%s] must immediately follow by try block, and unlock operation must be placed in the first line of finally block.]]>\n    </entry>\n    <entry key=\"java.concurrent.LockShouldWithTryFinallyRule.rule.msg\">\n        <![CDATA[When getting the lock by blocking methods, such as waiting in the blocking queue, lock() must be put outside the try block. Besides, make sure there is no method that throws Exception between the lock() and try block, in case the lock won't be released in the finally block.\nExplain 1: If there was any Exception thrown between the lock() and try block, it won't be able to release the lock, causing that the other threads cannot get the lock.\nExplain 2: If there was lock() in the try block and a method that throw Exception between the try block and lock(), it is possible that unlock() won't work. Then AQS(AbstractQueuedSynchronizer) method will be called(depends on the implementation of the class) and IllegalMonitorStateException will be thrown.\nExplain 3: It is possible that when implementing the lock() method in Lock object, it would throw unchecked Exception, resulting in the same outcome of the Explain 2.]]>\n    </entry>\n    <!-- flowcontrol -->\n    <entry key=\"java.flowcontrol.SwitchStatementRule.violation.nodefault\">\n        <![CDATA[missing default statement in switch block]]>\n    </entry>\n    <entry key=\"java.flowcontrol.SwitchStatementRule.violation.notermination\">\n        <![CDATA[every case should end with break or return etc.]]>\n    </entry>\n    <entry key=\"java.flowcontrol.SwitchStatementRule.rule.msg\">\n        <![CDATA[ In a switch block, each case should be finished by break/return. If not, a note should be included to describe at which case it will stop. Within every switch block, a default statement must be present, even if it is empty.]]>\n    </entry>\n\n    <entry key=\"java.flowcontrol.NeedBraceRule.violation.msg\">\n        <![CDATA[missing brace in %s statement]]>\n    </entry>\n    <entry key=\"java.flowcontrol.NeedBraceRule.rule.msg\">\n        <![CDATA[Braces are used with if, else, for, do and while statements, even if the body contains only a single statement. Avoid using the following example: if (condition) statements;]]>\n    </entry>\n\n    <entry key=\"java.flowcontrol.AvoidComplexConditionRule.violation.msg\">\n        <![CDATA[Do not use complicated statements in conditional statements]]>\n    </entry>\n    <entry key=\"java.flowcontrol.AvoidComplexConditionRule.rule.msg\">\n        <![CDATA[Do not use complicated statements in conditional statements (except for frequently used methods like getXxx/isXxx). Use boolean variables to store results of complicated statements temporarily will increase the code's readability.]]>\n    </entry>\n    <entry key=\"java.flowcontrol.AvoidComplexConditionRule.rule.desc\">\n        <![CDATA[Note: Logic within many if statements are very complicated. Readers need to analyze the final results of the conditional expression to decide what statement is to be executed in certain conditions.]]>\n    </entry>\n\n    <entry key=\"java.flowcontrol.AvoidNegationOperatorRule.violation.msg\">\n        <![CDATA[The negation operator is not easy to be quickly understood.]]>\n    </entry>\n    <entry key=\"java.flowcontrol.AvoidNegationOperatorRule.rule.msg\">\n        <![CDATA[Avoid using the negation operator '!'.]]>\n    </entry>\n    <entry key=\"java.flowcontrol.AvoidNegationOperatorRule.rule.desc\">\n        <![CDATA[Note: The negation operator is not easy to be quickly understood. There must be a positive way to represent the same logic.]]>\n    </entry>\n\n    <!-- set -->\n    <entry key=\"java.set.ClassCastExceptionWithSubListToArrayListRule.violation.msg\">\n        <![CDATA[The result of [%s] can't cast in class ArrayList]]>\n    </entry>\n    <entry key=\"java.set.ClassCastExceptionWithSubListToArrayListRule.rule.msg\">\n        <![CDATA[Do not cast subList in class ArrayList, otherwise ClassCastException will be thrown. ]]>\n    </entry>\n    <entry key=\"java.set.ClassCastExceptionWithSubListToArrayListRule.rule.msg.desc\">\n        <![CDATA[Note:Do not cast, if you have to do, please use new Conllection(sublist result). ]]>\n    </entry>\n    <entry key=\"java.set.ClassCastExceptionWithToArrayRule.violation.msg\">\n        <![CDATA[[%s] should use arguments with  array size.]]>\n    </entry>\n    <entry key=\"java.set.ClassCastExceptionWithToArrayRule.rule.msg\">\n        <![CDATA[Do not use toArray method without arguments. Since the return type is Object[], ClassCastException will be thrown when casting it to a different array type.]]>\n    </entry>\n    <entry key=\"java.set.CollectionInitShouldAssignCapacityRule.violation.msg\">\n        <![CDATA[[%s] should set a size when initializing ]]>\n    </entry>\n    <entry key=\"java.set.CollectionInitShouldAssignCapacityRule.rule.msg\">\n        <![CDATA[Set a size when initializing a collection if possible.]]>\n    </entry>\n    <entry key=\"java.set.CollectionInitShouldAssignCapacityRule.rule.msg.desc\">\n        <![CDATA[Note:HashMap does not set the size of the capacity, with the elements continue to increase, the capacity is often forced to expand, resize the need to rebuild the hash table, seriously affecting performance.]]>\n    </entry>\n    <entry key=\"java.set.ConcurrentExceptionWithModifyOriginSubListRule.violation.msg\">\n        <![CDATA[[%s] could cause ConcurrentModificationException]]>\n    </entry>\n    <entry key=\"java.set.ConcurrentExceptionWithModifyOriginSubListRule.rule.msg\">\n        <![CDATA[When using subList, be careful to modify the size of original list. It might cause ConcurrentModificationException when performing traversing, adding or deleting on the subList.]]>\n    </entry>\n    <entry key=\"java.set.DontModifyInForeachCircleRule.violation.msg\">\n        <![CDATA[Do not use [%s] to a collection in a foreach loop.]]>\n    </entry>\n    <entry key=\"java.set.DontModifyInForeachCircleRule.rule.msg\">\n        <![CDATA[Do not remove or add elements to a collection in a foreach loop. Please use Iterator to remove an item. Iterator object should be synchronized when executing concurrent operations.]]>\n    </entry>\n    <entry key=\"java.set.UnsupportedExceptionWithModifyAsListRule.violation.msg\">\n        <![CDATA[Use [%s] can cause UnsupportedOperationException ]]>\n    </entry>\n    <entry key=\"java.set.UnsupportedExceptionWithModifyAsListRule.rule.msg\">\n        <![CDATA[Do not use methods which will modify the list after using Arrays.asList to convert array to list, otherwise methods like add/remove/clear will throw UnsupportedOperationException. ]]>\n    </entry>\n    <!-- constant -->\n    <entry key=\"java.constant.UndefineMagicConstantRule.violation.msg\">\n        <![CDATA[Magic value [%s] ]]>\n    </entry>\n    <entry key=\"java.constant.UndefineMagicConstantRule.rule.msg\">\n        <![CDATA[Magic values, except for predefined, are forbidden in coding.]]>\n    </entry>\n    <entry key=\"java.constant.UpperEllRule.violation.msg\">\n        <![CDATA[ [%s] shoud use upper L ]]>\n    </entry>\n    <entry key=\"java.constant.UpperEllRule.rule.msg\">\n        <![CDATA[ 'L' instead of 'l' should be used for long or Long variable because 'l' is easily to be regarded as number 1 in mistake.]]>\n    </entry>\n\n    <!-- oop -->\n    <entry key=\"java.oop.EqualsAvoidNullRule.violation.msg\">\n        <![CDATA[[%s] should be argument of equals, but not caller]]>\n    </entry>\n    <entry key=\"java.oop.EqualsAvoidNullRule.rule.msg\">\n        <![CDATA[Since NullPointerException can possibly be thrown while calling the equals method of Object, equals should be invoked by a constant or an object that is definitely not null.]]>\n    </entry>\n\n    <entry key=\"java.oop.WrapperTypeEqualityRule.violation.msg\">\n        <![CDATA[should use equals method instead of ==]]>\n    </entry>\n    <entry key=\"java.oop.WrapperTypeEqualityRule.rule.msg\">\n        <![CDATA[The wrapper classes should be compared by equals method rather than by symbol of '==' directly.]]>\n    </entry>\n    <entry key=\"java.oop.WrapperTypeEqualityRule.rule.desc\">\n        <![CDATA[Note: Consider this assignment: Integer var = ?. When it fits the range from -128 to 127, we can use == directly for a comparison. Because the Integer object will be generated by IntegerCache.cache, which reuses an existing object. Nevertheless, when it fits the complementary set of the former range, the Integer object will be allocated in Heap, which does not reuse an existing object. This is a pitfall. Hence the equals method is recommended.]]>\n    </entry>\n\n    <entry key=\"java.oop.PojoMustUsePrimitiveFieldRule.violation.msg\">\n        <![CDATA[field [%s] should use wrapper type]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustUsePrimitiveFieldRule.rule.msg\">\n        <![CDATA[\n Rules for using primitive data types and wrapper classes:\n 1) Members of a POJO class must be wrapper classes.\n 2) The return value and arguments of a RPC method must be wrapper classes.\n 3) [Recommended] Local variables should be primitive data types.\n        ]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustUsePrimitiveFieldRule.rule.msg.desc\">\n        <![CDATA[Note: In order to remind the consumer of explicit assignments, there are no initial values for members in a POJO class. As a consumer, you should check problems such as NullPointerException and warehouse entries for yourself.]]>\n    </entry>\n\n    <entry key=\"java.oop.PojoNoDefaultValueRule.violation.msg\">\n        <![CDATA[field [%s] should not has default value]]>\n    </entry>\n    <entry key=\"java.oop.PojoNoDefaultValueRule.rule.msg\">\n        <![CDATA[While defining POJO classes like DO, DTO, VO, etc., do not assign any default values to the members.]]>\n    </entry>\n\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.violation.msg.notostring\">\n        <![CDATA[[%s] not override the toString method]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.violation.msg.usesuper\">\n        <![CDATA[should call super.toString]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.rule.msg\">\n        <![CDATA[The toString method must be implemented in a POJO class. The super.toString method should be called in front of the whole implementation if the current class extends another POJO class.]]>\n    </entry>\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.rule.desc\">\n        <![CDATA[ We can call the toString method in a POJO directly to print property values in order to check the problem when a method throws an exception in runtime.]]>\n    </entry>\n\n    <entry key=\"java.oop.PojoMustOverrideToStringRule.violation.msg\">\n        <![CDATA[do not concat string with \"+\" in loop]]>\n    </entry>\n    <entry key=\"java.oop.StringConcatRule.rule.msg\">\n        <![CDATA[Use the append method in StringBuilder inside a loop body when concatenating multiple strings.]]>\n    </entry>\n    <entry key=\"java.oop.StringConcatRule.rule.msg.desc\">\n        <![CDATA[Note: According to the decompiled bytecode file, for each loop, it allocates a StringBuilder object, appends a string, and finally returns a String object via the toString method. This is a tremendous waste of memory.]]>\n    </entry>\n\n    <entry key=\"java.oop.BigDecimalAvoidDoubleConstructorRule.violation.msg\">\n        <![CDATA[Constructor BigDecimal(double) is invoked]]>\n    </entry>\n    <entry key=\"java.oop.BigDecimalAvoidDoubleConstructorRule.rule.msg\">\n        <![CDATA[Avoid using the constructor BigDecimal(double) to convert double value to a BigDecimal object.]]>\n    </entry>\n    <entry key=\"java.oop.BigDecimalAvoidDoubleConstructorRule.rule.msg.desc\">\n        <![CDATA[Note：Use the constructor BigDecimal(String) or valueOf method of BigDecimal. Inside valueOf the toString of Double is executed, which truncate the mantissa according to the precision of double.]]>\n    </entry>\n\n    <!-- comment -->\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.rule.msg\">\n        <![CDATA[Javadoc should be used for classes, class variables and methods. The format should be '/** comment **/', rather than '// xxx'.]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.rule.desc\">\n        <![CDATA[\nIn IDE, Javadoc can be seen directly when hovering, which is a good way to improve efficiency.\n        ]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.class\">\n        <![CDATA[class [%s] should use javadoc format comment]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.constructor.default\">\n        <![CDATA[constructor [%s()] should use javadoc format comment]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.constructor.parameter\">\n        <![CDATA[constructor [%s(%s)] should use javadoc format comment]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.method\">\n        <![CDATA[method [%s] should use javadoc format comment]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.field\">\n        <![CDATA[field [%s] should use javadoc format comment]]>\n    </entry>\n    <entry key=\"java.comment.CommentsMustBeJavadocFormatRule.violation.msg.enum\">\n        <![CDATA[enum [%s] should use javadoc format comment]]>\n    </entry>\n\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.rule.msg\">\n        <![CDATA[Abstract methods (including methods in interface) should be commented by Javadoc.]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.rule.desc\">\n        <![CDATA[\nJavadoc should include method instruction, description of parameters, return values and possible exceptions.\n        ]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.abstract\">\n        <![CDATA[abstract method [%s] should have javadoc]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.interface\">\n        <![CDATA[method [%s] in interface should have javadoc]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.desc\">\n        <![CDATA[please javadoc the purpose of method [%s] in detail]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.parameter\">\n        <![CDATA[method [%s] should have javadoc for parameter [%s]]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.return\">\n        <![CDATA[return value of method [%s] should have javadoc]]>\n    </entry>\n    <entry key=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.violation.msg.exception\">\n        <![CDATA[method [%s] should have javadoc for exception [%s]]]>\n    </entry>\n\n    <entry key=\"java.comment.AvoidCommentBehindStatementRule.rule.msg\">\n        <![CDATA[Single line comments in a method should be put above the code to be commented, by using // and multiple lines by using /* */.]]>\n    </entry>\n    <entry key=\"java.comment.AvoidCommentBehindStatementRule.violation.msg\">\n        <![CDATA[avoid put comment behind statement]]>\n    </entry>\n\n    <entry key=\"java.comment.ClassMustHaveAuthorRule.rule.msg\">\n        <![CDATA[Every class should include information of author(s) and date.]]>\n    </entry>\n    <entry key=\"java.comment.ClassMustHaveAuthorRule.rule.desc\">\n        <![CDATA[\nNote: When setting template in IDE, the format of author in IDEA is ${USER}, while in Eclipse is ${user} (Case sensitive).\nThe format of date is 'yyyy/MM/dd'.\n        ]]>\n    </entry>\n    <entry key=\"java.comment.ClassMustHaveAuthorRule.violation.msg.comment\">\n        <![CDATA[[%s] should have @author javadoc]]>\n    </entry>\n    <entry key=\"java.comment.ClassMustHaveAuthorRule.violation.msg.author\">\n        <![CDATA[javadoc of [%s] should contain @author tag]]>\n    </entry>\n\n    <entry key=\"java.comment.EnumConstantsMustHaveCommentRule.rule.msg\">\n        <![CDATA[All enumeration type fields should be commented as Javadoc style.]]>\n    </entry>\n    <entry key=\"java.comment.EnumConstantsMustHaveCommentRule.violation.msg\">\n        <![CDATA[fields of enum [%s] should have javadoc]]>\n    </entry>\n\n    <entry key=\"java.comment.RemoveCommentedCodeRule.rule.msg\">\n        <![CDATA[Codes or configuration that is noticed to be obsoleted should be resolutely removed from projects.]]>\n    </entry>\n    <entry key=\"java.comment.RemoveCommentedCodeRule.rule.desc\">\n        <![CDATA[\nNote: Remove obsoleted codes or configuration in time to avoid code redundancy.\n        ]]>\n    </entry>\n\n\n    <!-- jave other -->\n    <entry key=\"java.other.AvoidPatternCompileInMethodRule.rule.msg\">\n        <![CDATA[When using regex, precompile needs to be done in order to increase the matching performance.]]>\n    </entry>\n    <entry key=\"java.other.AvoidPatternCompileInMethodRule.rule.desc\">\n        <![CDATA[\nNote: Do not define Pattern pattern = Pattern.compile(.); within method body.\n        ]]>\n    </entry>\n    <entry key=\"java.other.AvoidPatternCompileInMethodRule.violation.msg\">\n        <![CDATA[variable [%s] should be defined as constant or field]]>\n    </entry>\n\n    <entry key=\"java.other.AvoidApacheBeanUtilsCopyRule.rule.msg\">\n        <![CDATA[Avoid using *Apache Beanutils* to copy attributes.]]>\n    </entry>\n    <entry key=\"java.other.AvoidApacheBeanUtilsCopyRule.rule.desc\">\n        <![CDATA[\nNote: *Spring BeanUtils* and *Cglib BeanCopier* are recommended to be used, which have better performance.\n        ]]>\n    </entry>\n\n    <entry key=\"java.other.AvoidNewDateGetTimeRule.rule.msg\">\n        <![CDATA[Use System.currentTimeMillis() to get the current millisecond. Do not use new Date().getTime(). ]]>\n    </entry>\n    <entry key=\"java.other.AvoidNewDateGetTimeRule.rule.desc\">\n        <![CDATA[\nNote: In order to get a more accurate time, use System.nanoTime(). In JDK8, use Instant class to deal with situations like time statistics.\n        ]]>\n    </entry>\n    <entry key=\"java.other.AvoidNewDateGetTimeRule.violation.msg\">\n        <![CDATA[please use System.currentTimeMillis() instead of new Date().getTime()]]>\n    </entry>\n\n    <entry key=\"java.other.AvoidMissUseOfMathRandomRule.rule.msg\">\n        <![CDATA[The return type of Math.random() is double, value range is 0<=x<1 (0 is possible). If a random integer is required, do not multiply x by 10 then round the result. The correct way is to use nextInt or nextLong method which belong to Random Object.]]>\n    </entry>\n\n    <entry key=\"java.other.MethodTooLongRule.rule.msg\">\n        <![CDATA[The total number of lines for a method should not be more than 80.]]>\n    </entry>\n\n    <entry key=\"java.other.MethodTooLongRule.rule.desc\">\n        <![CDATA[\nNote: The total number of lines, including the method signature, closing brace, codes, blank lines, line breaks and any invisible lines, should not be more than 80 (comments are not included).\n        ]]>\n    </entry>\n\n    <entry key=\"java.other.MethodTooLongRule.violation.msg\">\n        <![CDATA[The total number of lines for method [%s] should not be more than 80.]]>\n    </entry>\n\n    <entry key=\"java.other.UseRightCaseForDateFormatRule.rule.msg\">\n        <![CDATA[Date format string [%s] is error,When doing date formatting, 'y' should be written in lowercase for 'year'.]]>\n    </entry>\n    <entry key=\"java.other.UseRightCaseForDateFormatRule.rule.desc\">\n        <![CDATA[When doing date formatting, \"yyyy\" represents the day in which year, while \"YYYY\" represents the week in which\n * year (a concept introduced in JDK7). If a week is across two years, the returning \"YYYY\"represents the next year.]]>\n    </entry>\n\n\n    <!--other -->\n    <entry key=\"vm.other.UseQuietReferenceNotationRule.rule.msg\">\n        <![CDATA[Variables must add exclamatory mark when passing to velocity engine from backend, ${var}--add '!' after '$'.]]>\n    </entry>\n    <entry key=\"vm.other.UseQuietReferenceNotationRule.rule.desc\">\n        <![CDATA[\nNote: If attribute is null or does not exist, ${var} will be shown directly on web pages.\n        ]]>\n    </entry>\n    <entry key=\"vm.other.UseQuietReferenceNotationRule.violation.msg\">\n        <![CDATA[variable [%s] should add ! after $]]>\n    </entry>\n\n    <entry key=\"java.other.AvoidDoubleOrFloatEqualCompareRule.rule.msg\">\n        <![CDATA[To judge the equivalence of floating-point numbers, == cannot be used for primitive types, while equals cannot be used for wrapper classes.]]>\n    </entry>\n    <entry key=\"java.other.AvoidDoubleOrFloatEqualCompareRule.rule.desc\">\n        <![CDATA[\nFloating-point numbers are composed by mantissa and exponent, which is similar to the coefficient and exponent of scientific notation. Most decimal fractions cannot be represented precisely by binary. For more details please refer to \"Easy Coding\".\nPositive example:\n1) Specify an error range. Consider two floating-pointing numbers as equal if the difference between them is within this range.\n\n    float a = 1.0f - 0.9f;\n    float b = 0.9f - 0.8f;\n    float diff = 1e-6f;\n\n    if (Math.abs(a - b) < diff) {\n        System.out.println(\"true\");\n    }\n2) Use BigDecimal to operate.\n\n    BigDecimal a = new BigDecimal(\"1.0\");\n    BigDecimal b = new BigDecimal(\"0.9\");\n    BigDecimal c = new BigDecimal(\"0.8\");\n\n    BigDecimal x = a.subtract(b);\n    BigDecimal y = b.subtract(c);\n\n    if (x.equals(y)) {\n        System.out.println(\"true\");\n    }\n        ]]>\n    </entry>\n    <entry key=\"java.other.AvoidDoubleOrFloatEqualCompareRule.rule.msg\">\n        <![CDATA[To judge the equivalence of floating-point numbers, == cannot be used for primitive types, while equals cannot be used for wrapper classes.]]>\n    </entry>\n\n</properties>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/namelist.properties",
    "content": "ConstantFieldShouldBeUpperCaseRule_LOG_VARIABLE_TYPE_SET=[\"Log\",\"Logger\"]\nConstantFieldShouldBeUpperCaseRule_WHITE_LIST=[\"serialVersionUID\"]\nLowerCamelCaseVariableNamingRule_WHITE_LIST=[\"DAOImpl\"]\nPojoMustOverrideToStringRule_POJO_SUFFIX_SET=[\"DO\",\"DTO\",\"VO\",\"BO\"]\nUndefineMagicConstantRule_LITERAL_WHITE_LIST=[\"0\",\"1\",\"\\\\\\\"\\\\\\\"\",\"0.0\",\"1.0\",\"-1\",\"0L\",\"1L\"]\nMethodReturnWrapperTypeRule_PRIMITIVE_TYPE_TO_WAPPER_TYPE={\"int\":\"Integer\",\"boolean\":\"Boolean\",\"float\":\"Float\",\"double\":\"Double\",\"byte\":\"Byte\",\"short\":\"Short\",\"long\":\"Long\",\"char\":\"Character\"}\nCollectionInitShouldAssignCapacityRule_COLLECTION_TYPE=[\"HashMap\",\"ConcurrentHashMap\"]\nClassNamingShouldBeCamelRule_CLASS_NAMING_WHITE_LIST=[\"Hbase\",\"HBase\",\"ID\"]\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-comment.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaComments\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaComments</description>\n\n    <rule name=\"CommentsMustBeJavadocFormatRule\" message=\"java.comment.CommentsMustBeJavadocFormatRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.comment.CommentsMustBeJavadocFormatRule\">\n        <description>java.comment.CommentsMustBeJavadocFormatRule.rule.desc</description>\n        <priority>3</priority>\n\n        <example>\n<![CDATA[\n    /**\n     * \n     * XXX class function description.\n     *\n     */\n    public class XxClass implements Serializable {\n        private static final long serialVersionUID = 113323427779853001L;\n        /**\n         * id\n         */\n        private Long id;\n        /**\n         * title\n         */\n        private String title;\n    \n        /**\n         * find by id\n         * \n         * @param ruleId rule id\n         * @param page start from 1\n         * @return Result<Xxxx>\n         */\n        public Result<Xxxx> funcA(Long ruleId, Integer page) {\n            return null;\n        }\n    }\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"AbstractMethodOrInterfaceMethodMustUseJavadocRule\"\n        message=\"java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule\">\n        <description>java.comment.AbstractMethodOrInterfaceMethodMustUseJavadocRule.rule.desc</description>\n        <priority>3</priority>\n\n        <example>\n<![CDATA[\n    /**\n     * fetch data by rule id\n     * \n     * @param ruleId rule id\n     * @param page page number\n     * @param jsonContext json format context\n     * @return Result<XxxxDO>\n     */\n    Result<XxxxDO> fetchDataByRuleId(Long ruleId, Integer page, String jsonContext);\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"ClassMustHaveAuthorRule\" message=\"java.comment.ClassMustHaveAuthorRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.comment.ClassMustHaveAuthorRule\">\n        <description>java.comment.ClassMustHaveAuthorRule.rule.desc</description>\n        <priority>3</priority>\n\n        <example>\n<![CDATA[\n    /**\n     * Demo class\n     * \n     * @author keriezhang\n     * @date 2016/10/31\n     */\n    public class CodeNoteDemo {\n    }\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"EnumConstantsMustHaveCommentRule\" message=\"java.comment.EnumConstantsMustHaveCommentRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.comment.EnumConstantsMustHaveCommentRule\">\n        <priority>2</priority>\n\n        <example>\n<![CDATA[\n    public enum TestEnum {\n        /**\n         * agree\n         */\n        agree(\"agree\"),\n        /**\n         * reject\n         */\n        reject(\"reject\");\n        \n        private String action;\n    \n        TestEnum(String action) {\n            this.action = action;\n        }\n    \n        public String getAction() {\n            return action;\n        }\n    }\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"AvoidCommentBehindStatementRule\"\n        message=\"java.comment.AvoidCommentBehindStatementRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.comment.AvoidCommentBehindStatementRule\">\n        <priority>3</priority>\n\n        <example>\n<![CDATA[\n    public void method() {\n        // Put single line comment above code. (Note: align '//' comment with code)\n        int a = 3;\n    \n        /**\n        * Some description about follow code. (Note: align '/**' comment with code)\n        */\n        int b = 4;\n    }\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"RemoveCommentedCodeRule\"\n          message=\"java.comment.RemoveCommentedCodeRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.comment.RemoveCommentedCodeRule\">\n        <description>java.comment.RemoveCommentedCodeRule.rule.desc</description>\n        <priority>3</priority>\n        <example>\n<![CDATA[\nPositive example: For codes which are temporarily removed and likely to be reused, use /// to add a reasonable note.\n public static void hello() {\n    /// Business is stopped temporarily by the owner.\n    // Business business = new Business();\n    // business.active();\n    System.out.println(\"it's finished\");\n}\n]]>\n        </example>\n    </rule>\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-concurrent.xml",
    "content": "<?xml version=\"1.0\"?>\n<ruleset name=\"AlibabaJavaConcurrent\"\n         xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaConcurrent</description>\n\n    <rule name=\"ThreadPoolCreationRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.ThreadPoolCreationRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.ThreadPoolCreationRule\">\n        <description>java.concurrent.ThreadPoolCreationRule.rule.desc</description>\n        <priority>1</priority>\n        <example>\n            <![CDATA[\nPositive example 1：\n    //org.apache.commons.lang3.concurrent.BasicThreadFactory\n    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,\n        new BasicThreadFactory.Builder().namingPattern(\"example-schedule-pool-%d\").daemon(true).build());\n       ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example 2：\n    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()\n        .setNameFormat(\"demo-pool-%d\").build();\n\n    //Common Thread Pool\n    ExecutorService pool = new ThreadPoolExecutor(5, 200,\n        0L, TimeUnit.MILLISECONDS,\n        new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());\n\n    pool.execute(()-> System.out.println(Thread.currentThread().getName()));\n    pool.shutdown();//gracefully shutdown\n       ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example 3：\n    <bean id=\"userThreadPool\"\n        class=\"org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor\">\n        <property name=\"corePoolSize\" value=\"10\" />\n        <property name=\"maxPoolSize\" value=\"100\" />\n        <property name=\"queueCapacity\" value=\"2000\" />\n\n    <property name=\"threadFactory\" value= threadFactory />\n        <property name=\"rejectedExecutionHandler\">\n            <ref local=\"rejectedExecutionHandler\" />\n        </property>\n    </bean>\n    //in code\n    userThreadPool.execute(thread);\n       ]]>\n        </example>\n    </rule>\n    <rule name=\"AvoidUseTimerRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.AvoidUseTimerRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.AvoidUseTimerRule\">\n        <priority>1</priority>\n        <example>\n            <![CDATA[\n    //org.apache.commons.lang3.concurrent.BasicThreadFactory\n    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,\n        new BasicThreadFactory.Builder().namingPattern(\"example-schedule-pool-%d\").daemon(true).build());\n    executorService.scheduleAtFixedRate(new Runnable() {\n        @Override\n        public void run() {\n            //do something\n        }\n    },initialDelay,period, TimeUnit.HOURS);\n       ]]>\n        </example>\n    </rule>\n    <rule name=\"AvoidManuallyCreateThreadRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.AvoidManuallyCreateThreadRule.rule.msg\"\n          dfa=\"true\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.AvoidManuallyCreateThreadRule\">\n        <description>java.concurrent.AvoidManuallyCreateThreadRule.rule.desc</description>\n        <priority>2</priority>\n        <example>\n            <![CDATA[\n    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()\n        .setNameFormat(\"demo-pool-%d\").build();\n    ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,\n        0L, TimeUnit.MILLISECONDS,\n        new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());\n\n    singleThreadPool.execute(()-> System.out.println(Thread.currentThread().getName()));\n    singleThreadPool.shutdown();\n    ]]>\n        </example>\n    </rule>\n    <rule name=\"ThreadShouldSetNameRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.ThreadShouldSetNameRule.rule.msg\"\n          dfa=\"true\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.ThreadShouldSetNameRule\">\n        <priority>2</priority>\n        <example>\n            <![CDATA[\n    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()\n        .setNameFormat(\"demo-pool-%d\").build();\n    ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,\n        0L, TimeUnit.MILLISECONDS,\n        new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());\n\n    singleThreadPool.execute(()-> System.out.println(Thread.currentThread().getName()));\n    singleThreadPool.shutdown();\n    ]]>\n        </example>\n        <example>\n            <![CDATA[\n    public class TimerTaskThread extends Thread {\n        public TimerTaskThread(){\n        super.setName(\"TimerTaskThread\"); …\n    }\n       ]]>\n        </example>\n    </rule>\n    <rule name=\"AvoidCallStaticSimpleDateFormatRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.AvoidCallStaticSimpleDateFormatRule.rule.msg\"\n          dfa=\"true\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.AvoidCallStaticSimpleDateFormatRule\">\n        <description>java.concurrent.AvoidCallStaticSimpleDateFormatRule.rule.desc</description>\n        <priority>2</priority>\n        <example>\n            <![CDATA[\nPositive example 1：\n    private static final String FORMAT = \"yyyy-MM-dd HH:mm:ss\";\n    public String getFormat(Date date){\n        SimpleDateFormat dateFormat = new SimpleDateFormat(FORMAT);\n        return sdf.format(date);\n    }\n        ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example 2：\n    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n    public void getFormat(){\n        synchronized (sdf){\n        sdf.format(new Date());\n        ….;\n    }\n        ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example 3：\n    private static final ThreadLocal<DateFormat> DATE_FORMATTER = new ThreadLocal<DateFormat>() {\n        @Override\n        protected DateFormat initialValue() {\n            return new SimpleDateFormat(\"yyyy-MM-dd\");\n        }\n    };\n        ]]>\n        </example>\n    </rule>\n\n    <rule name=\"ThreadLocalShouldRemoveRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.ThreadLocalShouldRemoveRule.rule.msg\"\n          dfa=\"true\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.ThreadLocalShouldRemoveRule\">\n        <priority>2</priority>\n        <example>\n            <![CDATA[\n    /**\n     * @author caikang\n     * @date 2017/04/07\n     */\n    public class UserHolder {\n        private static final ThreadLocal<User> userThreadLocal = new ThreadLocal<User>();\n\n        public static void set(User user){\n            userThreadLocal.set(user);\n        }\n\n        public static User get(){\n            return userThreadLocal.get();\n        }\n\n        public static void remove(){\n            userThreadLocal.remove();\n        }\n    }\n\n    /**\n     * @author caikang\n     * @date 2017/04/07\n     */\n    public class UserInterceptor extends HandlerInterceptorAdapter {\n        @Override\n        public boolean preHandle(HttpServletRequest request,\n            HttpServletResponse response, Object handler) throws Exception {\n            UserHolder.set(new User());\n            return true;\n        }\n\n        @Override\n        public void afterCompletion(HttpServletRequest request,\n            HttpServletResponse response, Object handler, Exception ex) throws Exception {\n            UserHolder.remove();\n        }\n    }\n        ]]>\n        </example>\n    </rule>\n    <rule name=\"AvoidConcurrentCompetitionRandomRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.AvoidConcurrentCompetitionRandomRule.rule.msg\"\n          dfa=\"true\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.AvoidConcurrentCompetitionRandomRule\">\n        <priority>3</priority>\n        <example>\n            <![CDATA[\nPositive example 1：\n    /**\n     * @author caikang\n     * @date 2017/04/07\n     */\n    public class RandomInThread extends Thread {\n        private Random random = new Random();\n\n        @Override\n        public void run() {\n            long t = random.nextLong();\n        }\n    }\n        ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example 2：\n    /**\n     * @author caikang\n     * @date 2017/04/07\n     */\n    public class RandomInThread extends Thread {\n        private Random random = ThreadLocalRandom.current();\n\n        @Override\n        public void run() {\n            long t = random.nextLong();\n        }\n    }\n        ]]>\n        </example>\n    </rule>\n    <rule name=\"CountDownShouldInFinallyRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.CountDownShouldInFinallyRule.rule.msg\"\n          dfa=\"true\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.CountDownShouldInFinallyRule\">\n        <description>java.concurrent.CountDownShouldInFinallyRule.rule.desc</description>\n        <priority>3</priority>\n        <example>\n            <![CDATA[\n    /**\n     * @author caikang\n     * @date 2017/04/07\n     */\n    public class CountDownExample {\n        public void operate(CountDownLatch countDownLatch){\n            try{\n                System.out.println(\"business logic\");\n            }catch (RuntimeException e){\n                // do something\n            }finally {\n                countDownLatch.countDown();\n            }\n        }\n    }\n        ]]>\n        </example>\n    </rule>\n    <rule name=\"LockShouldWithTryFinallyRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.concurrent.LockShouldWithTryFinallyRule.rule.msg\"\n          dfa=\"true\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.concurrent.LockShouldWithTryFinallyRule\">\n        <description>java.concurrent.LockShouldWithTryFinallyRule.rule.desc</description>\n        <priority>1</priority>\n        <example>\n            <![CDATA[\nPositive example：\n    Lock lock = new XxxLock();\n    // ...\n    lock.lock();\n    try {\n        doSomething();\n        doOthers();\n    } finally {\n        lock.unlock();\n    }\n        ]]>\n        </example>\n        <example>\n            <![CDATA[\nNegative example：\n    Lock lock = new XxxLock();\n    // ...\n    try {\n        // If an exception is thrown here, the finally block is executed directly\n        doSomething();\n        // The finally block executes regardless of whether the lock is successful or not\n        lock.lock();\n        doOthers();\n\n    } finally {\n        lock.unlock();\n    }\n        ]]>\n        </example>\n    </rule>\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-constant.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaConstants\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaConstants</description>\n\n    <rule name=\"UpperEllRule\"\n        message=\"java.constant.UpperEllRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.constant.UpperEllRule\">\n        <priority>1</priority>\n        <example>\n      <![CDATA[\nNegative example:\n    //It is hard to tell whether it is number 11 or Long 1.\n    Long warn = 1l;\n       ]]>\n        </example>\n        <example>\n        <![CDATA[\nPositive example:\n    Long notwarn = 1L;\n        ]]>\n         </example>\n    </rule>\n\n    <rule name=\"UndefineMagicConstantRule\"\n        message=\"java.constant.UndefineMagicConstantRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.constant.UndefineMagicConstantRule\">\n        <priority>3</priority>\n\n        <example>\n        <![CDATA[\nNegative example:\n    //Magic values, except for predefined, are forbidden in coding.\n    if (key.equals(\"Id#taobao_1\")) {\n            //...\n    }\n         ]]>\n        </example>\n        <example>\n        <![CDATA[\nPositive example:\n    String KEY_PRE = \"Id#taobao_1\";\n    if (KEY_PRE.equals(key)) {\n            //...\n    }\n      ]]>\n      </example>\n    </rule>\n\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-exception.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaExceptions\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaExceptions</description>\n\n    <rule name=\"MethodReturnWrapperTypeRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.exception.MethodReturnWrapperTypeRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.exception.MethodReturnWrapperTypeRule\">\n        <priority>3</priority>\n        <example>\n            <![CDATA[\n    public int method() {\n        Integer a = null;\n        return a;\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"AvoidReturnInFinallyRule\"\n          language=\"java\"\n          message=\"java.exception.AvoidReturnInFinallyRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.exception.AvoidReturnInFinallyRule\">\n        <priority>2</priority>\n        <example>\n            <![CDATA[\nNegative example:\n    public static Long readFileLength(String fileName) {\n        try {\n            File file = new File(fileName);\n            RandomAccessFile randomAccessFile = new RandomAccessFile(file, \"r\");\n            return randomAccessFile.length();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        } finally {\n            countDownLatch.countDown();\n            return 0L;\n        }\n    }\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"TransactionMustHaveRollbackRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.exception.TransactionMustHaveRollbackRule.rule.msg\"\n          dfa=\"true\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.exception.TransactionMustHaveRollbackRule\">\n        <priority>3</priority>\n        <example>\n            <![CDATA[\nPositive example 1：\n    /**\n     * @author caikang\n     * @date 2017/04/07\n     */\n    @Service\n    @Transactional(rollbackFor = Exception.class)\n    public class UserServiceImpl implements UserService {\n        @Override\n        public void save(User user) {\n            //some code\n            //db operation\n        }\n    }\n        ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example 2：\n    /**\n     * @author caikang\n     * @date 2017/04/07\n     */\n    @Service\n    public class UserServiceImpl implements UserService {\n        @Override\n        @Transactional(rollbackFor = Exception.class)\n        public void save(User user) {\n            //some code\n            //db operation\n        }\n    }\n        ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example 3：\n    /**\n     * @author caikang\n     * @date 2017/04/07\n     */\n    @Service\n    public class UserServiceImpl implements UserService {\n        @Autowired\n        private DataSourceTransactionManager transactionManager;\n\n        @Override\n        @Transactional\n        public void save(User user) {\n            DefaultTransactionDefinition def = new DefaultTransactionDefinition();\n            // explicitly setting the transaction name is something that can only be done programmatically\n            def.setName(\"SomeTxName\");\n            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);\n\n            TransactionStatus status = transactionManager.getTransaction(def);\n            try {\n                // execute your business logic here\n                //db operation\n            } catch (Exception ex) {\n                transactionManager.rollback(status);\n                throw ex;\n            }\n        }\n    }\n        ]]>\n        </example>\n    </rule>\n\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-flowcontrol.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaFlowControl\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaFlowControl</description>\n\n    <rule name=\"SwitchStatementRule\"\n          language=\"java\"\n          message=\"java.flowcontrol.SwitchStatementRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.flowcontrol.SwitchStatementRule\">\n        <priority>2</priority>\n\n        <example>\n            <![CDATA[\n    switch (x) {\n        case 1:\n            break;\n        case 2:\n            break;\n        default:\n    }\n\t\t\t]]>\n        </example>\n    </rule>\n\n    <rule name=\"NeedBraceRule\"\n          language=\"java\"\n          message=\"java.flowcontrol.NeedBraceRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.flowcontrol.NeedBraceRule\">\n        <priority>1</priority>\n\n        <example>\n            <![CDATA[\n    if (flag) {\n            System.out.println(\"hello world\");\n    }\n\t\t\t]]>\n        </example>\n    </rule>\n\n    <rule name=\"AvoidComplexConditionRule\"\n          language=\"java\"\n          message=\"java.flowcontrol.AvoidComplexConditionRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.flowcontrol.AvoidComplexConditionRule\">\n        <description>java.flowcontrol.AvoidComplexConditionRule.rule.desc</description>\n        <priority>3</priority>\n\n        <example>\n            <![CDATA[\nNegative example:\n    if ((file.open(fileName, \"w\") != null) && (...) || (...)) {\n        // ...\n    }\n\t\t\t]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example:\n    boolean existed = (file.open(fileName, \"w\") != null) && (...) || (...);\n    if (existed) {\n        //...\n    }\n\t\t\t]]>\n        </example>\n    </rule>\n\n    <rule name=\"AvoidNegationOperatorRule\"\n          language=\"java\"\n          message=\"java.flowcontrol.AvoidNegationOperatorRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.flowcontrol.AvoidNegationOperatorRule\">\n        <description>java.flowcontrol.AvoidNegationOperatorRule.rule.desc</description>\n        <priority>3</priority>\n\n        <example>\n            <![CDATA[\nNegative example:\n    // Use `if (!(x >= 628))` to represent that x is less than 628.\n    if (!(x >= 628)) {\n        // ...\n    }\n\t\t\t]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example:\n    // Use `if (x < 628)` to represent that x is less than 628.\n    if (x < 628)) {\n        // ...\n    }\n\t\t\t]]>\n        </example>\n    </rule>\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-naming.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaNaming\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaNaming</description>\n\n\n    <rule name=\"ClassNamingShouldBeCamelRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.ClassNamingShouldBeCamelRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.ClassNamingShouldBeCamelRule\">\n        <priority>3</priority>\n    </rule>\n\n    <rule name=\"AbstractClassShouldStartWithAbstractNamingRule\"\n          language=\"java\"\n          since=\"1.4\"\n          message=\"java.naming.AbstractClassShouldStartWithAbstractNamingRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.AbstractClassShouldStartWithAbstractNamingRule\">\n        <priority>2</priority>\n        <example>\n            <![CDATA[\n    abstract class BaseControllerDemo{\n    }\n\n    abstract class AbstractActionDemo{\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"ExceptionClassShouldEndWithExceptionRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.ExceptionClassShouldEndWithExceptionRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.ExceptionClassShouldEndWithExceptionRule\">\n        <priority>2</priority>\n        <example>\n            <![CDATA[\n    public class CacheDemoException extends Exception{\n    }\n            ]]>\n        </example>\n    </rule>\n\n\n    <rule name=\"TestClassShouldEndWithTestNamingRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.TestClassShouldEndWithTestNamingRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.TestClassShouldEndWithTestNamingRule\">\n        <priority>3</priority>\n        <example>\n            <![CDATA[\n    public class DemoTest {\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"LowerCamelCaseVariableNamingRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.LowerCamelCaseVariableNamingRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.LowerCamelCaseVariableNamingRule\">\n        <priority>2</priority>\n    </rule>\n\n    <rule name=\"AvoidStartWithDollarAndUnderLineNamingRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.AvoidStartWithDollarAndUnderLineNamingRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.AvoidStartWithDollarAndUnderLineNamingRule\">\n        <priority>2</priority>\n    </rule>\n\n    <rule name=\"ConstantFieldShouldBeUpperCaseRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.ConstantFieldShouldBeUpperCaseRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.ConstantFieldShouldBeUpperCaseRule\">\n        <priority>2</priority>\n        <example>\n            <![CDATA[\n    public class ConstantNameDemo {\n\n    /**\n    * max stock count\n    */\n    public static final Long MAX_STOCK_COUNT = 50000L;\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"ServiceOrDaoClassShouldEndWithImplRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.ServiceOrDaoClassShouldEndWithImplRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.ServiceOrDaoClassShouldEndWithImplRule\">\n        <priority>2</priority>\n        <example>\n            <![CDATA[\n    public interface DemoService{\n        void f();\n    }\n\n    public class DemoServiceImpl implements DemoService {\n        @Override\n        public void f(){\n            System.out.println(\"hello world\");\n        }\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"PackageNamingRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.PackageNamingRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.PackageNamingRule\">\n        <priority>3</priority>\n        <example>\n            <![CDATA[\n    com.alibaba.mpp.util / com.taobao.tddl.domain.dto\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"BooleanPropertyShouldNotStartWithIsRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.BooleanPropertyShouldNotStartWithIsRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.BooleanPropertyShouldNotStartWithIsRule\">\n        <priority>2</priority>\n        <example>\n            <![CDATA[\n    public class DemoDO{\n        Boolean success;\n        Boolean delete;\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"ArrayNamingShouldHaveBracketRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.ArrayNamingShouldHaveBracketRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.naming.ArrayNamingShouldHaveBracketRule\">\n        <priority>3</priority>\n        <example>\n            <![CDATA[\n    String[] a = new String[3];\n            ]]>\n        </example>\n    </rule>\n\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-oop.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaOop\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaOop</description>\n\n    <rule name=\"EqualsAvoidNullRule\"\n          language=\"java\"\n          message=\"java.oop.EqualsAvoidNullRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.oop.EqualsAvoidNullRule\">\n        <priority>2</priority>\n\n        <example>\n            <![CDATA[\n    public void f(String str){\n        String inner = \"hi\";\n        if (inner.equals(str)) {\n            System.out.println(\"hello world\");\n        }\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"WrapperTypeEqualityRule\"\n          language=\"java\"\n          message=\"java.oop.WrapperTypeEqualityRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.oop.WrapperTypeEqualityRule\">\n        <description>java.oop.WrapperTypeEqualityRule.rule.desc</description>\n        <priority>1</priority>\n\n        <example>\n            <![CDATA[\n    Integer a = 235;\n    Integer b = 235;\n    if (a.equals(b)) {\n        // code\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"PojoMustUsePrimitiveFieldRule\"\n          language=\"java\"\n          message=\"java.oop.PojoMustUsePrimitiveFieldRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.oop.PojoMustUsePrimitiveFieldRule\">\n        <description>java.oop.PojoMustUsePrimitiveFieldRule.rule.msg.desc</description>\n        <priority>3</priority>\n\n        <example>\n            <![CDATA[\n    public class DemoDO {\n        String str;\n        Integer a;\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"PojoNoDefaultValueRule\"\n          language=\"java\"\n          message=\"java.oop.PojoNoDefaultValueRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.oop.PojoNoDefaultValueRule\">\n        <priority>3</priority>\n\n        <example>\n            <![CDATA[\n    public class DemoDO {\n        String str;\n        Integer a;\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"PojoMustOverrideToStringRule\"\n          language=\"java\"\n          message=\"java.oop.PojoMustOverrideToStringRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.oop.PojoMustOverrideToStringRule\">\n        <description>java.oop.PojoMustOverrideToStringRule.rule.desc</description>\n        <priority>3</priority>\n\n        <example>\n            <![CDATA[\n    public class ToStringDemo extends Super{\n        private String secondName;\n\n        @Override\n        public String toString() {\n            return super.toString() + \"ToStringDemo{\" + \"secondName='\" + secondName + '\\'' + '}';\n        }\n    }\n\n    class Super {\n        private String firstName;\n\n        @Override\n        public String toString() {\n            return \"Super{\" + \"firstName=\" + firstName + '\\'' + '}';\n        }\n    }\n            ]]>\n        </example>\n    </rule>\n\n    <rule name=\"StringConcatRule\"\n          language=\"java\"\n          message=\"java.oop.StringConcatRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.oop.StringConcatRule\">\n        <description>java.oop.StringConcatRule.rule.msg.desc</description>\n        <priority>3</priority>\n\n        <example>\n            <![CDATA[\nNegative example:\n    String result;\n    for (String string : tagNameList) {\n        result = result + string;\n    }\n]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example:\n    StringBuilder stringBuilder = new StringBuilder();\n    for (String string : tagNameList) {\n        stringBuilder.append(string);\n    }\n    String result = stringBuilder.toString();\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"BigDecimalAvoidDoubleConstructorRule\"\n          language=\"java\"\n          message=\"java.oop.BigDecimalAvoidDoubleConstructorRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.oop.BigDecimalAvoidDoubleConstructorRule\">\n        <description>java.oop.BigDecimalAvoidDoubleConstructorRule.rule.msg.desc</description>\n        <priority>3</priority>\n\n        <example>\n            <![CDATA[\nNegative example:\n    BigDecimal good1 = new BigDecimal(0.1);\n]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example:\n    BigDecimal good1 = new BigDecimal(\"0.1\");\n    BigDecimal good2 = BigDecimal.valueOf(0.1);\n]]>\n        </example>\n    </rule>\n\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-orm.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaOrm\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaOrm</description>\n\n    <rule name=\"IbatisMethodQueryForListRule\"\n          language=\"java\"\n          since=\"1.6\"\n          message=\"java.naming.IbatisMethodQueryForListRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.orm.IbatisMethodQueryForListRule\">\n        <priority>3</priority>\n    </rule>\n\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-other.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaOthers\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaOthers</description>\n\n    <rule name=\"AvoidPatternCompileInMethodRule\" language=\"java\"\n        message=\"java.other.AvoidPatternCompileInMethodRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.other.AvoidPatternCompileInMethodRule\">\n        <description>java.other.AvoidPatternCompileInMethodRule.rule.desc</description>\n        <priority>1</priority>\n        <example>\n<![CDATA[\n    public class XxxClass {\n        // Use precompile\n        private static Pattern NUMBER_PATTERN = Pattern.compile(\"[0-9]+\");\n        public Pattern getNumberPattern() {\n            // Avoid use Pattern.compile in method body.\n            Pattern localPattern = Pattern.compile(\"[0-9]+\");\n            return localPattern;\n        }\n    }\n]]>\n      </example>\n    </rule>\n\n    <rule name=\"AvoidApacheBeanUtilsCopyRule\" language=\"java\"\n        message=\"java.other.AvoidApacheBeanUtilsCopyRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.other.AvoidApacheBeanUtilsCopyRule\">\n        <description>java.other.AvoidApacheBeanUtilsCopyRule.rule.desc</description>\n        <priority>1</priority>\n        <example>\n<![CDATA[\n    TestObject a = new TestObject();\n    TestObject b = new TestObject();\n    a.setX(b.getX());\n    a.setY(b.getY());\n]]>\n      </example>\n    </rule>\n\n    <rule name=\"AvoidNewDateGetTimeRule\" language=\"java\"\n        message=\"java.other.AvoidNewDateGetTimeRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.other.AvoidNewDateGetTimeRule\">\n        <description>java.other.AvoidNewDateGetTimeRule.rule.desc</description>\n        <priority>1</priority>\n        <example>\n<![CDATA[\n    public class TimeMillisDemo {\n        public static void main(String args[]) {\n            // Positive example:\n            long a = System.currentTimeMillis();\n            // Negative example:\n            long b = new Date().getTime();\n\n            System.out.println(a);\n            System.out.println(b);\n        }\n    }\n]]>\n      </example>\n    </rule>\n\n    <rule name=\"AvoidMissUseOfMathRandomRule\" language=\"java\"\n          message=\"java.other.AvoidMissUseOfMathRandomRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.other.AvoidMissUseOfMathRandomRule\">\n        <priority>3</priority>\n        <example>\n<![CDATA[\nNegative example:\n    Long randomLong =(long) (Math.random() * 10);\n]]>\n        </example>\n        <example>\n<![CDATA[\nPositive example:\n    Long randomLong = new Random().nextLong();\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"MethodTooLongRule\" language=\"java\"\n          message=\"java.other.MethodTooLongRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.other.MethodTooLongRule\">\n        <description>java.other.MethodTooLongRule.rule.desc</description>\n        <priority>3</priority>\n    </rule>\n\n    <rule name=\"UseRightCaseForDateFormatRule\" language=\"java\"\n          message=\"java.other.UseRightCaseForDateFormatRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.other.UseRightCaseForDateFormatRule\">\n        <description>java.other.UseRightCaseForDateFormatRule.rule.desc</description>\n        <priority>2</priority>\n        <example>\n            <![CDATA[\nNegative example:\n    SimpleDateFormat format = new SimpleDateFormat(\"yyyy-mm-dd HH:mm:ss\");\n ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example:\n        SimpleDateFormat format = new SimpleDateFormat(\"YYYY-MM-dd HH:mm:ss\");\n]]>\n        </example>\n    </rule>\n\n    <rule name=\"AvoidDoubleOrFloatEqualCompareRule\" language=\"java\"\n          message=\"java.other.AvoidDoubleOrFloatEqualCompareRule.rule.msg\"\n          class=\"com.alibaba.p3c.pmd.lang.java.rule.other.AvoidDoubleOrFloatEqualCompareRule\">\n        <description>java.other.AvoidDoubleOrFloatEqualCompareRule.rule.desc</description>\n        <priority>2</priority>\n        <example>\n            <![CDATA[\nNegative example:\n        float g = 0.7f-0.6f;\n        float h = 0.8f-0.7f;\n        if (g == h) {\n            System.out.println(\"true\");\n        }\n ]]>\n        </example>\n        <example>\n            <![CDATA[\nPositive example:\n        double dis = 1e-6;\n        double d1 = 0.0000001d;\n        double d2 = 0d;\n        System.out.println(Math.abs(d1 - d2) < dis);\n]]>\n        </example>\n    </rule>\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/java/ali-set.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaJavaSets\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaJavaSets</description>\n\n    <rule name=\"ClassCastExceptionWithToArrayRule\"\n        message=\"java.set.ClassCastExceptionWithToArrayRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.set.ClassCastExceptionWithToArrayRule\">\n        <priority>2</priority>\n        <example>\n        <![CDATA[\nNegative example:  \n   Integer[] a = (Integer [])c.toArray();\n        ]]>\n        </example>\n        <example>\n        <![CDATA[\nPositive example： \n   Integer[] b = (Integer [])c.toArray(new Integer[c.size()]); \n         ]]>\n        </example>\n    </rule>\n\n    <rule name=\"UnsupportedExceptionWithModifyAsListRule\"\n        message=\"java.set.UnsupportedExceptionWithModifyAsListRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.set.UnsupportedExceptionWithModifyAsListRule\">\n        <priority>2</priority>\n        <example>\n       <![CDATA[\nPositive example:\n   List<String> t   = Arrays.asList(\"a\",\"b\",\"c\"); \n   //warn\n   t.add(\"22\");\n   //warn\n   t.remove(\"22\");\n   //warn\n   t.clear(); \n         ]]>\n         </example>\n    </rule>\n\n    <rule name=\"ClassCastExceptionWithSubListToArrayListRule\"\n        message=\"java.set.ClassCastExceptionWithSubListToArrayListRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.set.ClassCastExceptionWithSubListToArrayListRule\">\n        <description>java.set.ClassCastExceptionWithSubListToArrayListRule.rule.msg.desc</description>\n        <priority>2</priority>\n        <example>\n        <![CDATA[\nNegative example:\n   List<String> list = new ArrayList<String>();\n   list.add(\"22\");\n   //warn\n   List<String> test = (ArrayList<String>) list.subList(0, 1);\t \n         ]]>\n        </example>\n        <example>\n        <![CDATA[\nPositive example:\n   List<String> list2 = new ArrayList<String>(list.subList(0, 1));\n         ]]>\n         </example>\n    </rule>\n\n    <rule name=\"ConcurrentExceptionWithModifyOriginSubListRule\"\n        message=\"java.set.ConcurrentExceptionWithModifyOriginSubListRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.set.ConcurrentExceptionWithModifyOriginSubListRule\">\n        <priority>2</priority>\n        <example>\n      <![CDATA[\nNegative example:                \n   List<String> originList = new ArrayList<String>();\n   originList.add(\"22\");\n   List<String> subList = originList.subList(0, 1);\n   //warn\n   originList.add(\"22\"); \n       ]]>\n         </example>\n    </rule>\n\n\n    <rule name=\"DontModifyInForeachCircleRule\"\n        message=\"java.set.DontModifyInForeachCircleRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.set.DontModifyInForeachCircleRule\">\n        <priority>1</priority>\n\n        <example>\n        <![CDATA[\n Negative example:   \n   List<String> originList = new ArrayList<String>();\n   originList.add(\"22\");\n   for (String item : originList) { \n      //warn\n      list.add(\"bb\");\n   }  \n        ]]>\n       </example>\n      <example>\n       <![CDATA[\n Positive example: \n   Iterator<Integer> it=b.iterator();\t\t \n   while(it.hasNext()){                      \n      Integer temp =  it.next();             \n      if (delCondition) {\n          it.remove();\n      }\n   }\n         ]]>\n      </example>\n    </rule>\n\n    <rule name=\"CollectionInitShouldAssignCapacityRule\"\n        message=\"java.set.CollectionInitShouldAssignCapacityRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.java.rule.set.CollectionInitShouldAssignCapacityRule\">\n        <description>java.set.CollectionInitShouldAssignCapacityRule.rule.msg.desc</description>\n        <priority>3</priority>\n        <example>\n        <![CDATA[\n Negative example:   \n   Map<String, String> map = new HashMap<String, String>();\n    \n        ]]>\n       </example>\n      <example>\n       <![CDATA[\n Positive example: \n   Map<String, String> map = new HashMap<String, String>(16);\n         ]]>\n      </example>\n    </rule>\n\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/main/resources/rulesets/vm/ali-other.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<ruleset name=\"AlibabaVelocityOthers\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n    <description>AlibabaVelocityOthers</description>\n    <rule name=\"UseQuietReferenceNotationRule\" language=\"vm\"\n        message=\"vm.other.UseQuietReferenceNotationRule.rule.msg\"\n        class=\"com.alibaba.p3c.pmd.lang.vm.rule.other.UseQuietReferenceNotationRule\">\n        <description>vm.other.UseQuietReferenceNotationRule.rule.desc</description>\n        <priority>3</priority>\n        <example>\n<![CDATA[\n    <input type=\"text\" name=\"email\" value=\"$!email\"/>\n    <input type=\"text\" name=\"email\" value=\"$!{email}\"/>\n]]>\n      </example>\n    </rule>\n\n</ruleset>\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/comment/CommentRulesTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.comment;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for comment rules.\n * \n * @author keriezhang\n * @date 2017/06/18\n *\n */\npublic class CommentRulesTest extends SimpleAggregatorTst {\n\n    private static final String RULESET = \"java-ali-comment\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"CommentsMustBeJavadocFormatRule\");\n        addRule(RULESET, \"AbstractMethodOrInterfaceMethodMustUseJavadocRule\");\n        addRule(RULESET, \"ClassMustHaveAuthorRule\");\n        addRule(RULESET, \"EnumConstantsMustHaveCommentRule\");\n        addRule(RULESET, \"AvoidCommentBehindStatementRule\");\n        addRule(RULESET, \"RemoveCommentedCodeRule\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/concurrent/ConcurrentRuleTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for concurrent rules.\n *\n * @author caikang\n * @date 2016/11/14\n *\n */\npublic class ConcurrentRuleTest extends SimpleAggregatorTst {\n    private static final String RULE_NAME = \"java-ali-concurrent\";\n\n    @Override\n    public void setUp() {\n        addRule(RULE_NAME, \"ThreadPoolCreationRule\");\n        addRule(RULE_NAME, \"AvoidUseTimerRule\");\n        addRule(RULE_NAME, \"AvoidManuallyCreateThreadRule\");\n        addRule(RULE_NAME, \"ThreadShouldSetNameRule\");\n        addRule(RULE_NAME, \"AvoidCallStaticSimpleDateFormatRule\");\n        addRule(RULE_NAME, \"ThreadLocalShouldRemoveRule\");\n        addRule(RULE_NAME, \"AvoidConcurrentCompetitionRandomRule\");\n        addRule(RULE_NAME, \"CountDownShouldInFinallyRule\");\n        addRule(RULE_NAME, \"LockShouldWithTryFinallyRule\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/constant/ConstantRulesTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.constant;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for constant rules.\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n *\n */\npublic class ConstantRulesTest extends SimpleAggregatorTst {\n\n    private static final String RULESET = \"java-ali-constant\";\n    \n    @Override\n    public void setUp() {\n        addRule(RULESET, \"UpperEllRule\");\n        addRule(RULESET, \"UndefineMagicConstantRule\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/exception/ExceptionRulesTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.exception;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for exception rules.\n *\n * @author changle.lq\n * @date 2016/11/23\n *\n */\npublic class ExceptionRulesTest extends SimpleAggregatorTst {\n    private static final String RULESET = \"java-ali-exception\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"MethodReturnWrapperTypeRule\");\n        addRule(RULESET, \"AvoidReturnInFinallyRule\");\n        addRule(RULESET, \"TransactionMustHaveRollbackRule\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/FlowControlRuleTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.flowcontrol;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for flowcontrol rules.\n *\n * @author zenghou.fw\n * @date 2017/04/11\n *\n */\npublic class FlowControlRuleTest extends SimpleAggregatorTst {\n\n    private static final String RULESET = \"java-ali-flowcontrol\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"SwitchStatementRule\");\n        addRule(RULESET, \"NeedBraceRule\");\n        addRule(RULESET, \"AvoidComplexConditionRule\");\n        addRule(RULESET, \"AvoidNegationOperatorRule\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/naming/NamingRulesTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.naming;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for naming rules.\n *\n * @author changle.lq\n * @date 2016/11/23\n *\n */\npublic class NamingRulesTest extends SimpleAggregatorTst {\n    private static final String RULESET = \"java-ali-naming\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"ClassNamingShouldBeCamelRule\");\n        addRule(RULESET, \"AbstractClassShouldStartWithAbstractNamingRule\");\n        addRule(RULESET, \"ExceptionClassShouldEndWithExceptionRule\");\n        addRule(RULESET, \"TestClassShouldEndWithTestNamingRule\");\n        addRule(RULESET, \"LowerCamelCaseVariableNamingRule\");\n        addRule(RULESET, \"AvoidStartWithDollarAndUnderLineNamingRule\");\n        addRule(RULESET, \"ConstantFieldShouldBeUpperCaseRule\");\n        addRule(RULESET, \"ServiceOrDaoClassShouldEndWithImplRule\");\n        addRule(RULESET, \"BooleanPropertyShouldNotStartWithIsRule\");\n        addRule(RULESET, \"ArrayNamingShouldHaveBracketRule\");\n        addRule(RULESET, \"PackageNamingRule\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/oop/OopRuleTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.oop;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for oop rules.\n *\n * @author zenghou.fw\n * @date 2016/11/29\n *\n */\npublic class OopRuleTest extends SimpleAggregatorTst {\n\n    // 加载CLASSPATH下的rulesets/java/ali-oop.xml\n    private static final String RULESET = \"java-ali-oop\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"EqualsAvoidNullRule\");\n        addRule(RULESET, \"WrapperTypeEqualityRule\");\n        addRule(RULESET, \"PojoNoDefaultValueRule\");\n        addRule(RULESET, \"PojoMustUsePrimitiveFieldRule\");\n        addRule(RULESET, \"PojoMustOverrideToStringRule\");\n        addRule(RULESET, \"StringConcatRule\");\n        addRule(RULESET, \"BigDecimalAvoidDoubleConstructorRule\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/orm/OrmRulesTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.orm;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for orm rules.\n *\n * @author changle.lq\n * @date 2016/11/23\n *\n */\npublic class OrmRulesTest extends SimpleAggregatorTst {\n    private static final String RULESET = \"java-ali-orm\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"IbatisMethodQueryForListRule\");\n    }\n}"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/other/OtherRulesTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\nimport org.junit.Test;\n\n/**\n * Test for other java rules.\n *\n * @author keriezhang\n * @date 2017/06/18\n *\n */\npublic class OtherRulesTest extends SimpleAggregatorTst {\n\n    public static final String RULESET = \"java-ali-other\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"AvoidApacheBeanUtilsCopyRule\");\n        addRule(RULESET, \"AvoidNewDateGetTimeRule\");\n        addRule(RULESET, \"AvoidPatternCompileInMethodRule\");\n        addRule(RULESET, \"AvoidMissUseOfMathRandomRule\");\n        addRule(RULESET, \"MethodTooLongRule\");\n        addRule(RULESET,\"UseRightCaseForDateFormatRule\");\n        addRule(RULESET,\"AvoidDoubleOrFloatEqualCompareRule\");\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/other/UseRightCaseForDateFormatRuleTest.java",
    "content": "package com.alibaba.p3c.pmd.lang.java.rule.other;\n\nimport com.alibaba.p3c.pmd.testframework.ExtendRuleTst;\n\nimport net.sourceforge.pmd.Rule;\nimport org.junit.Test;\n\n/**\n * @author huawen.phw\n * @date 2018/2/1\n * Description:\n */\npublic class UseRightCaseForDateFormatRuleTest extends ExtendRuleTst {\n\n    @Test\n    public void testExam1() {\n        String ruleName = \"UseRightCaseForDateFormatRule\";\n        String examFilePath = \"java/\" + ruleName + \"Exam.java\";\n        String expectedVioLineNumbers = \"16,26,32,34,36\";\n\n        Rule rule = findRule(OtherRulesTest.RULESET, ruleName);\n        runTest(rule, examFilePath, expectedVioLineNumbers);\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/java/rule/set/SetRulesTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.java.rule.set;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for set rules.\n *\n * @author shengfang.gsf\n * @date 2016/12/13\n */\npublic class SetRulesTest extends SimpleAggregatorTst {\n\n    private static final String RULESET = \"java-ali-set\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"ClassCastExceptionWithSubListToArrayListRule\");\n        addRule(RULESET, \"ClassCastExceptionWithToArrayRule\");\n        addRule(RULESET, \"CollectionInitShouldAssignCapacityRule\");\n        addRule(RULESET, \"ConcurrentExceptionWithModifyOriginSubListRule\");\n        addRule(RULESET, \"DontModifyInForeachCircleRule\");\n        addRule(RULESET, \"UnsupportedExceptionWithModifyAsListRule\");\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/lang/vm/rule/other/OtherRulesTest.java",
    "content": "/*\n * Copyright 1999-2017 Alibaba Group.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.p3c.pmd.lang.vm.rule.other;\n\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n * Test for other vm rules.\n * \n * @author keriezhang\n * @date 2017/06/18\n *\n */\npublic class OtherRulesTest extends SimpleAggregatorTst {\n\n    private static final String RULESET = \"vm-ali-other\";\n\n    @Override\n    public void setUp() {\n        addRule(RULESET, \"UseQuietReferenceNotationRule\");\n    }\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/testframework/ExtendRuleTst.java",
    "content": "package com.alibaba.p3c.pmd.testframework;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport net.sourceforge.pmd.Rule;\nimport net.sourceforge.pmd.testframework.RuleTst;\nimport net.sourceforge.pmd.testframework.TestDescriptor;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * @author huawen.phw\n * @date 2018/2/1\n * Description:\n */\npublic class ExtendRuleTst extends RuleTst {\n\n\n    public void runTest(Rule rule, String examFilePath, String expectedVioLineNumbers) {\n        TestDescriptor descriptor = extractTestsFromJavaFile(rule, examFilePath\n            , expectedVioLineNumbers);\n        if (descriptor != null) {\n            runTest(descriptor);\n        }\n    }\n\n    /**\n     * @param rule\n     * @return\n     */\n    public TestDescriptor extractTestsFromJavaFile(Rule rule) {\n        return extractTestsFromJavaFile(rule, \"java/\" + getCleanRuleName(rule) + \".java\");\n    }\n\n    /**\n     * @param rule\n     * @param javaFilePath\n     * @return\n     */\n    public TestDescriptor extractTestsFromJavaFile(Rule rule, String javaFilePath) {\n        return extractTestsFromJavaFile(rule, javaFilePath, \"\");\n    }\n\n    public TestDescriptor extractTestsFromJavaFile(Rule rule, String javaFilePath, String expectedLineNumbers) {\n        if (StringUtils.isEmpty(javaFilePath)) {\n            return null;\n        }\n        //append file suffix\n        if (!javaFilePath.toLowerCase().endsWith(\".java\")) {\n            javaFilePath = javaFilePath + \".java\";\n        }\n        InputStream inputStream = getClass().getResourceAsStream(javaFilePath);\n        if (inputStream == null) {\n            throw new RuntimeException(\"Couldn't find \" + javaFilePath);\n        }\n\n        String fileContents = null;\n        try {\n            fileContents = IOUtils.toString(inputStream, Charset.defaultCharset());\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            IOUtils.closeQuietly(inputStream);\n        }\n\n        if (fileContents == null) {\n            return null;\n        }\n        List<Integer> expectedLineNumber = getExpectedLineNumbers(expectedLineNumbers);\n        TestDescriptor descriptor = new TestDescriptor(fileContents, rule.getDescription(),\n            expectedLineNumber.size(), rule);\n        descriptor.setExpectedLineNumbers(expectedLineNumber);\n        return descriptor;\n    }\n\n    public List<Integer> getExpectedLineNumbers(String lineNumbers) {\n        List<Integer> expectedLineNumbers = new ArrayList<>();\n        for (String n : lineNumbers.split(\" *, *\")) {\n            try {\n                expectedLineNumbers.add(Integer.valueOf(n));\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n        return expectedLineNumbers;\n    }\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/java/com/alibaba/p3c/pmd/testframework/ExtendSimpleAggregatorTst.java",
    "content": "package com.alibaba.p3c.pmd.testframework;\n\nimport net.sourceforge.pmd.Rule;\nimport net.sourceforge.pmd.testframework.SimpleAggregatorTst;\n\n/**\n *\n * @author huawen.phw\n * @date 2018/2/1\n * Description: 扩展framework，runTest支持检查.java文件\n */\npublic  class ExtendSimpleAggregatorTst extends SimpleAggregatorTst {\n\n\n}\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/comment/xml/AbstractMethodOrInterfaceMethodMustUseJavadocRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\t<code-fragment id=\"non-abstract-method-in-abstract-class\"><![CDATA[\npublic abstract class AbstractClassOrInterfaceMethodMustUseJavadoc {\n    public String getName(String firstName, String secondName) throws XPathException, IOException {\n        return \"lalalala\";\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Non abstract method may have no comment.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"non-abstract-method-in-abstract-class\" />\n\t</test-code>\n\n\t<code-fragment id=\"abstract-method-without-comment-in-abstract-class\"><![CDATA[\npublic abstract class AbstractClassOrInterfaceMethodMustUseJavadoc {\n    public abstract String getName(String firstName, String secondName) throws XPathException, IOException;\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Abstract method have no comment.</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>2</expected-linenumbers>\n\t\t<code-ref id=\"abstract-method-without-comment-in-abstract-class\" />\n\t</test-code>\n\n\t<code-fragment id=\"abstract-method-with-part-of-comment-in-abstract-class\"><![CDATA[\npublic abstract class AbstractClassOrInterfaceMethodMustUseJavadoc {\n    /**\n     */\n    public abstract String getName(String firstName, String secondName) throws XPathException, IOException;\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Abstract method have part of javadoc comment about\n\t\t\tfunction, return, parameters and exceptions.\n\t\t</description>\n\t\t<expected-problems>6</expected-problems>\n\t\t<expected-linenumbers>4,4,4,4,4,4</expected-linenumbers>\n\t\t<code-ref id=\"abstract-method-with-part-of-comment-in-abstract-class\" />\n\t</test-code>\n\n\t<code-fragment id=\"abstract-method-with-full-comment-in-abstract-class\"><![CDATA[\npublic abstract class AbstractClassOrInterfaceMethodMustUseJavadoc {\n    /**\n     * only function comment.\n     */\n    public abstract void getFistName();\n\n    /**\n     * function comment\n     *\n     * @param firstName first name\n     * @param secondName second name\n     * @return full name\n     * @throws XPathException xpath exception\n     * @throws IOException IO exceptioin\n     */\n    public abstract String getName(String firstName, String secondName) throws XPathException, IOException;\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Abstract method have javadoc comment about function,\n\t\t\treturn, parameters and exceptions.\n\t\t</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"abstract-method-with-full-comment-in-abstract-class\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"method-in-interface-without-comment\"><![CDATA[\npublic interface AbstractClassOrInterfaceMethodMustUseJavadoc {\n    String getName(String firstName, String secondName) throws XPathException, IOException;\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Method in interface with non-javadoc comment.\n\t\t</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>2</expected-linenumbers>\n\t\t<code-ref id=\"method-in-interface-without-comment\" />\n\t</test-code>\n\n\t<code-fragment id=\"void-method-in-interface-with-part-of-comment\"><![CDATA[\npublic interface AbstractClassOrInterfaceMethodMustUseJavadoc {\n    /**\n     */\n    void getName();\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Void method with empty javadoc.</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>4</expected-linenumbers>\n\t\t<code-ref id=\"void-method-in-interface-with-part-of-comment\" />\n\t</test-code>\n\n\t<code-fragment id=\"method-in-interface-with-part-of-comment\"><![CDATA[\npublic interface AbstractClassOrInterfaceMethodMustUseJavadoc {\n    /**\n     */\n    String getName(String firstName, String secondName) throws XPathException, IOException;\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Method in interface have part of javadoc comment about\n\t\t\tfunction, return, parameters and exceptions.\n\t\t</description>\n\t\t<expected-problems>6</expected-problems>\n\t\t<expected-linenumbers>4,4,4,4,4,4</expected-linenumbers>\n\t\t<code-ref id=\"method-in-interface-with-part-of-comment\" />\n\t</test-code>\n\n\t<code-fragment id=\"method-in-interface-with-full-comment\"><![CDATA[\npublic interface AbstractClassOrInterfaceMethodMustUseJavadoc {\n    /**\n     * get user name\n     * \n     * @param firstName first name\n     * @param secondName second name\n     * @return full name\n     * @throws XPathException xpath exception\n     * @throws IOException io exception\n     */\n    String getName(String firstName, String secondName) throws XPathException, IOException;\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Method in interface have javadoc comment about\n\t\t\tfunction,\n\t\t\treturn, parameters and exceptions.\n\t\t</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"method-in-interface-with-full-comment\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"interface-ignore-methods-in-inner-enums-or-classes\"><![CDATA[\npublic interface InterfaceTest {\n   int test();\n   \n   int test2();\n   \n   public enum CmdbAttributeName {\n       schema(\"schema\"), planId(\"planId\");\n\n       private String prototype;\n\n       CmdbAttributeName(String prototype){\n           this.prototype = prototype;\n       }\n\n       public String getPrototype() {\n           return this.prototype;\n       }\n   }\n   \n   public class InnerClass {\n       public void classTest() {\n       };\n   }\n   \n   \n   String getName(String username);\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Interface ignore methods in inner enums or classes.\n\t\t</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>2,4,26</expected-linenumbers>\n\t\t<code-ref id=\"interface-ignore-methods-in-inner-enums-or-classes\" />\n\t</test-code>\n\n\t<code-fragment id=\"java8-interface\"><![CDATA[\npublic interface Stage {\n    /**\n     * test\n     */\n\tvoid test();\n\n    /**\n     * Process Stage\n     *\n     * @param context context of responsibility chain\n     */\n    void process(PipeLineContext context);\n\n    /**\n     * whether this stage can be skipped, true by default.\n     * @return  boolean  can skip or not.\n     */\n    default boolean isCanSkip() {\n        return true;\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Java8 Interface</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"java8-interface\" />\n\t</test-code>\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/comment/xml/AvoidCommentBehindStatementRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"comments-before-code\"><![CDATA[\npublic class AvoidCommentBehindStatementRule {\n    // comment above code 0\n    private String name;\n    public String getName() {\n        // comment above code 1\n        return this.name; \n    }\n    public void setName(String name) {\n        // comment above code 2\n        this.name = name; \n    }\n}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Comment before code</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"comments-before-code\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"comments-behind-code\"><![CDATA[\npublic class AvoidCommentBehindStatementRule {\n    private String name; // comment behind code 0\n    public String getName() {\n        return this.name; // comment behind code 1\n    }\n    public void setName(String name) {\n        this.name = name; // comment behind code 2\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Comments behind code</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>2,4,7</expected-linenumbers>\n\t\t<code-ref id=\"comments-behind-code\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"comments-behind-enum-constant\"><![CDATA[\npublic enum Level {\n    HIGH, // high level\n    MEDIUM, // medium level\n    LOW // low level\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Comments enum constant</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>2,3,4</expected-linenumbers>\n\t\t<code-ref id=\"comments-behind-enum-constant\" />\n\t</test-code>\n\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/comment/xml/ClassMustHaveAuthorRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"class-without-author\"><![CDATA[\npublic class ClassMustHaveAuthorRule {}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Class without author.</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>1</expected-linenumbers>\n\t\t<code-ref id=\"class-without-author\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"class-with-author\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2017/07/18\n */\npublic class ClassMustHaveAuthorRule {}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Class with author.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"class-with-author\" />\n\t</test-code>\n\n\t<code-fragment id=\"class-with-author-uppercase\"><![CDATA[\n/**\n * @Author keriezhang\n * @date 2017/07/18\n */\npublic class ClassMustHaveAuthorRule {}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Class with author uppercase.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"class-with-author-uppercase\" />\n\t</test-code>\n\n\t<code-fragment id=\"class-with-date\"><![CDATA[\n/**\n * @date 2016/12/14\n */\npublic class ClassMustHaveAuthorRule {}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Class with date.</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>4</expected-linenumbers>\n\t\t<code-ref id=\"class-with-date\" />\n\t</test-code>\n\n\t<code-fragment id=\"class-with-author-and-date\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class ClassMustHaveAuthorRule {}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Class with author and date.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"class-with-author-and-date\" />\n\t</test-code>\n\n\t<code-fragment id=\"class-with-inner-class\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class Outer_Demo {\n    public class Inner_Demo {\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Class with inner class.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"class-with-inner-class\" />\n\t</test-code>\n\n\t<code-fragment id=\"enum-without-author\"><![CDATA[\npublic enum Day {\n    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,\n    THURSDAY, FRIDAY, SATURDAY\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Enum without author</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>1</expected-linenumbers>\n\t\t<code-ref id=\"enum-without-author\" />\n\t</test-code>\n\n\t<code-fragment id=\"enum-with-author\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2016/12/14\n */\npublic enum Day {\n    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,\n    THURSDAY, FRIDAY, SATURDAY\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Enum with author</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"enum-with-author\" />\n\t</test-code>\n\n\t<code-fragment id=\"enum-in-class\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2016/12/14\n */\npublic class Vehicle {\n    private String id;\n    private String name;\n    enum color {\n        RED, GREEN, ANY;\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Enum in class</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"enum-in-class\" />\n\t</test-code>\n\n\t<code-fragment id=\"enum-in-interface\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2016/12/14\n */\npublic interface Vehicle {\n    public Number getNumber();\n    public void method2();\n    public enum color {\n        RED, GREEN, ANY;\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Enum in interface</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"enum-in-interface\" />\n\t</test-code>\n\n\t<code-fragment id=\"upper-case-author-annotation\"><![CDATA[\n/**\n * @Author keriezhang\n * @date 2016/12/14\n */\npublic interface Vehicle {\n    public Number getNumber();\n    public void method2();\n    public enum color {\n        RED, GREEN, ANY;\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Uppercase author annotation</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"upper-case-author-annotation\" />\n\t</test-code>\n\n\t<code-fragment id=\"annotation-type-without-author\"><![CDATA[\npublic @interface Vehicle {\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Annotation type without author</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>1</expected-linenumbers>\n\t\t<code-ref id=\"annotation-type-without-author\" />\n\t</test-code>\n\n\t<code-fragment id=\"annotation-type-with-author\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2018/11/07\n */\npublic @interface Vehicle {\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Annotation type with author</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"annotation-type-with-author\" />\n\t</test-code>\n\n\t<code-fragment id=\"annotation-type-inside-class\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2018/11/07\n */\npublic class NotEmpty {\n    public @interface List {\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Annotation type inside class</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"annotation-type-inside-class\" />\n\t</test-code>\n\n\t<code-fragment id=\"non-public-class\"><![CDATA[\n/**\n * @author keriezhang\n * @date 2018/11/07\n */\npublic class One {\n}\nclass Two {\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Non public class</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"non-public-class\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/comment/xml/CommentsMustBeJavadocFormatRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"class-without-comments\"><![CDATA[\npublic class CommentsMustBeJavadocFormat {\n    private String name;\n    public void getName() {}\n}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Class have no comment.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"class-without-comments\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"class-with-non-javadoc-comments\"><![CDATA[\n// a comment\n// a comment\npublic class CommentsMustBeJavadocFormat {\n    // a comment\n    private String name;\n    // a comment\n    public void getName() {}\n}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Class have non-javadoc comments.</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>2,4,6</expected-linenumbers>\n\t\t<code-ref id=\"class-with-non-javadoc-comments\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"class-with-javadoc-comments\"><![CDATA[\n/**\n * test\n */\npublic class CommentsMustBeJavadocFormat {\n    /**\n     * name\n     */\n    private String name;\n    \n    /**\n     * return name\n     */\n    public void getName() {}\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Class have javadoc comments.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"class-with-javadoc-comments\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"anonymous-class-with-non-javadoc-comments\"><![CDATA[\n// comment of outer class\npublic class Outer_class {\n   // comment of method of outer class\n   public void test() {\n      // comment of anonymous inner class\n      AnonymousInner inner = new AnonymousInner() {\n         // comment of method in anonymous inner class\n         public void mymethod() {\n            System.out.println(\"This is an example of anonymous inner class\");\n         }\n      };\n      inner.mymethod();\t\n   }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Anonymous Inner Class have non javadoc comments.\n\t\t</description>\n\t\t<expected-problems>2</expected-problems>\n\t\t<expected-linenumbers>1,3</expected-linenumbers>\n\t\t<code-ref id=\"anonymous-class-with-non-javadoc-comments\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"non-javadoc-comments-before-package-and-import\"><![CDATA[\n/*\n * Created on 18 nov. 2004\n */\n\npackage com.alibaba.pmd.test;\n\nimport java.util.ArrayList;\n// following import is important\nimport java.util.Comparator;\n\npublic class PMDProjectPropertyPage extends PropertyPage {\n    private Table buildAvailableRulesTableViewer(final Composite parent) {\n        return ruleTable;\n    }\n}\n\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Non-javadoc comments before package and import\n\t\t</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"non-javadoc-comments-before-package-and-import\" />\n\t</test-code>\n\n\t<code-fragment id=\"ignore-comments-behind-statements\"><![CDATA[\npublic class CommentsMustBeJavadocFormat {\n    private String name; //avoid two two violations in one line.\n    private Integer age;\n    public void getName() {\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Ignore comments behind statements.\n\t\t</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"ignore-comments-behind-statements\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/comment/xml/EnumConstantsMustHaveCommentRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"enum-without-comment\"><![CDATA[\npublic enum Level {\n    HIGH, MEDIUM, LOW\n}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Enum without Comment.</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>1</expected-linenumbers>\n\t\t<code-ref id=\"enum-without-comment\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"enum-with-comment\"><![CDATA[\npublic enum Level {\n    /**\n     * high, medium and low\n     */\n    HIGH, MEDIUM, LOW\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Enum with comment.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"enum-with-comment\" />\n\t</test-code>\n\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/comment/xml/RemoveCommentedCodeRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"commented-code\"><![CDATA[\n//import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\npublic class Test {\n    //private String name;\n    private Integer age;\n    //public String getName() {\n    //    return name;\n    //}\n    public Integer getAge() {\n        return age;\n    }\n    /*public void setName(String name) {\n        this.name = name;\n    }*/\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Commented Code</description>\n        <expected-problems>4</expected-problems>\n        <expected-linenumbers>1,3,7,11</expected-linenumbers>\n        <code-ref id=\"commented-code\" />\n    </test-code>\n\n\n    <code-fragment id=\"commented-code-with-three-slashes\"><![CDATA[\n/// no scan\n//import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\npublic class Test {\n    /// no scan\n    //private String name;\n    private Integer age;\n    /// no scan\n    //public String getName() {\n    //    return name;\n    //}\n    public Integer getAge() {\n        return age;\n    }\n    /// no scan\n    /*public void setName(String name) {\n        this.name = name;\n    }*/\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Commented code with three slashes</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"commented-code-with-three-slashes\" />\n    </test-code>\n\n\n    <code-fragment id=\"commented-code-with-anonymous-class\"><![CDATA[\npublic class Test {\n    public void test() {\n        // if (dtos.size() > 100 || dtos.size() == 0) {\n        //     return new RPCReturnResult().combineFail(\"invalid argument\");\n        // }\n        Collections.sort(dtos, new Comparator<TicketDto>() {\n            @Override\n            public int compare(TicketDto o1, TicketDto o2) {\n                return o1.getId().compareTo(o2.getId());\n            }\n        });\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Commented code with anonymous class</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>5</expected-linenumbers>\n        <code-ref id=\"commented-code-with-anonymous-class\" />\n    </test-code>\n\n    <code-fragment id=\"example-in-javadoc\"><![CDATA[\n/**\n * example: tair key = prefix|key.toString();\n */\npublic class Test {\n    /**\n     * example: test = test();\n     */\n    public void test() {\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Example in javadoc</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"example-in-javadoc\" />\n    </test-code>\n\n    <code-fragment id=\"code-without-pre-tag\"><![CDATA[\n/**\n * import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\n */\npublic class Test {\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Code without pre tag</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>1</expected-linenumbers>\n        <code-ref id=\"code-without-pre-tag\" />\n    </test-code>\n\n    <code-fragment id=\"code-in-pre-tag\"><![CDATA[\n/**\n * <pre>\n * import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;\n * </pre>\n */\npublic class Test {\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Code in pre tag</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"code-in-pre-tag\" />\n    </test-code>\n\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/AvoidCallStaticSimpleDateFormatRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <test-code>\n        <description>AvoidCallStaticSimpleDateFormatRule</description>\n        <expected-problems>4</expected-problems>\n        <expected-linenumbers>18,22,30,45</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.idea.pmd.rule.calendar;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * @author caikang\n * @date 2016/11/25\n */\npublic class SimpleDateFormatRule {\n    private static SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd\");\n\n    private Lock lock = new ReentrantLock();\n\n    private void test(){\n        String string = dateFormat.format(new Date());\n        synchronized (this){\n            dateFormat.format(new Date());\n        }\n        dateFormat.format(new Date());\n        lock.lock();\n        try {\n            dateFormat.format(new Date());\n            dateFormat.format(new Date());\n        }finally {\n            lock.unlock();\n        }\n        dateFormat.format(new Date());\n        lock.lock();\n        dateFormat.format(new Date());\n        try{\n        dateFormat.format(new Date());\n        }finally{\n            lock.unlock();\n        }\n    }\n\n    private synchronized void test1(){\n        dateFormat.format(new Date());\n    }\n\n    private void test2(){\n        dateFormat.format(new Date());\n    }\n}\n\n\n        ]]></code>\n    </test-code>\n\n    <test-code>\n        <description>call with lock</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.idea.pmd.rule.calendar;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * @author caikang\n * @date 2016/11/25\n */\npublic class SimpleDateFormatRule {\n    private static SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd\");\n\n    private Lock lock = new ReentrantLock();\n\n    private void test(){\n        synchronized (this){\n            dateFormat.format(new Date());\n        }\n        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy-MM-dd\");\n        simpleDateFormat.format(new Date());\n        lock.lock();\n        try {\n            dateFormat.format(new Date());\n            dateFormat.format(new Date());\n        }finally {\n            lock.unlock();\n        }\n    }\n\n    private synchronized void test1(){\n        dateFormat.format(new Date());\n    }\n\n}\n\n\n        ]]></code>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/AvoidConcurrentCompetitionRandomRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <test-code>\n        <description>AvoidConcurrentCompetitionRandomRule</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>13</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport java.util.Random;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class RandomTest extends Thread {\n    private static final Random RANDOM = new Random();\n\n    private void test(){\n        RANDOM.nextBoolean();\n    }\n}\n\n\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>AvoidConcurrentCompetitionRandomRule</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>13</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport java.util.Random;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class RandomTest extends Thread {\n    private static Random RANDOM = new Random();\n\n    private void test(){\n        RANDOM.nextBoolean();\n    }\n}\n\n\n        ]]></code>\n    </test-code>\n\n    <test-code>\n        <description>right</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport java.util.Random;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class RandomTest extends Thread {\n    private final Random RANDOM = new Random();\n\n    private void test(){\n        RANDOM.nextBoolean();\n    }\n}\n\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>right</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport java.util.Random;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class RandomTest extends Thread {\n    private static final Random RANDOM = new Random();\n\n    private void test(){\n        //RANDOM.nextBoolean();\n    }\n}\n\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>Math.random</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>9</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\n/**\n * @author caikang\n * @date 2017/03/30\n */\npublic class MathRandomTest extends Thread {\n    private void test(){\n        double d = Math.random();\n    }\n}\n\n\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>Math.random</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\n/**\n * @author caikang\n * @date 2017/03/30\n */\npublic class MathRandomTest extends Thread {\n    double d = Math.random();\n\n    private void test(){\n        //double d = Math.random();\n    }\n}\n\n\n        ]]></code>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/AvoidManuallyCreateThreadRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <test-code>\n        <description>AvoidManuallyCreateThreadRule</description>\n        <expected-problems>3</expected-problems>\n        <expected-linenumbers>16,19,23</expected-linenumbers>\n        <code><![CDATA[\n\npackage com.alibaba.idea.pmd.test.concurrent;\n\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author caikang\n * @date 2016/11/15\n */\npublic class ThreadCreateTest {\n    static {\n        new Thread();\n    }\n    private Thread thread = new Thread();\n\n    private Thread createThread(){\n        return new Thread();\n    }\n\n    public void testParamter(){\n    Thread thread = new Thread();\n\n    }\n\n}\n\n\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>right</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\n\npackage com.alibaba.idea.pmd.test.concurrent;\n\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author caikang\n * @date 2016/11/15\n */\npublic class ThreadCreateTest {\n     {\n        Runtime.getRuntime().addShutdownHook(\nnew Thread()\n);\n    }\n    private ThreadFactory threadFactory = r -> {\n        Thread thread1 = new Thread(r);\n        thread1.setName(\"kdsljf\");\n        return thread1;\n    };\n\n    private ThreadFactory threadFactory1 = new ThreadFactory() {\n        @Override\n        public Thread newThread(Runnable r) {\n            Thread thread = new Thread();\n            thread.setName(\"xxx\");\n            return thread;\n        }\n    };\n\n    private ThreadFactory threadFactory2 = new ThreadFactory() {\n        @Override\n        public Thread newThread(Runnable r) {\n            return new ThreadFactory() {\n                @Override\n                public Thread newThread(Runnable r) {\n                    Thread thread = new Thread();\n                    return thread;\n                }\n            }.newThread(r);\n        }\n    };\n\n    public void testNewThread(){\n        new ThreadFactory(){\n\n            @Override\n            public Thread newThread(Runnable r) {\n                return new Thread();\n            }\n        }.newThread(new Runnable() {\n            @Override\n            public void run() {\n\n            }\n        });\n    }\n\n    public void testParamter(){\n        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                r -> {\n                    Thread thread1 = new Thread(r);\n                    thread1.setName(\"xxx\");\n                    return thread1;\n                });\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                r -> {\n                    Thread thread1 = new Thread(r);\n                    thread1.setName(\"xxx\");\n                    return thread1;\n                });\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                new ThreadFactory() {\n                    @Override\n                    public Thread newThread(Runnable r) {\n                        return new Thread();\n                    }\n                });\n    }\n\n    class MyThreadFactory implements ThreadFactory {\n        /**\n         * Constructs a new {@code Thread}.  Implementations may also initialize\n         * priority, name, daemon status, {@code ThreadGroup}, etc.\n         *\n         * @param r a runnable to be executed by new thread instance\n         * @return constructed thread, or {@code null} if the request to create a thread is rejected\n         */\n        @Override\n        public Thread newThread(Runnable r) {\n            return new Thread();\n        }\n    }\n}\n\n\n        ]]></code>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/AvoidUseTimerRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\t<test-code>\n\t\t<description>AvoidUseTimer</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>10,13,14</expected-linenumbers>\n\t\t<code><![CDATA[\n\npackage com.alibaba.idea.pmd.test.concurrent;\n\nimport java.util.Timer;\n\n/**\n * @author caikang\n * @date 2016/11/15\n */\npublic class TimerTest {\n    private Timer timer = new Timer();\n\n    public void test(){\n        Timer t = new Timer();\n        new Timer();\n    }\n}\n\n        ]]></code>\n\t</test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/CountDownShouldInFinallyRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <test-code>\n        <description>CountDownShouldInFinallyRule</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>15</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport java.util.concurrent.CountDownLatch;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class CountDownTest {\n    private CountDownLatch countDownLatch = new CountDownLatch(5);\n\n    private void test(){\n        try{\n            System.out.println(\"dslkjf\");\n            countDownLatch.countDown();\n        }catch (Exception e){\n            e.printStackTrace();\n        }\n    }\n}\n\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>right</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport java.util.concurrent.CountDownLatch;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class CountDownTest {\n    private CountDownLatch countDownLatch = new CountDownLatch(5);\n\n    private void test(){\n        countDownLatch.countDown();\n        try{\n            System.out.println(\"dslkjf\");\n        }catch (Exception e){\n            e.printStackTrace();\n        }\n    }\n}\n\n\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>right</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport java.util.concurrent.CountDownLatch;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class CountDownTest {\n    private CountDownLatch countDownLatch = new CountDownLatch(5);\n\n    private void test(){\n        try{\n            System.out.println(\"dslkjf\");\n        }catch (Exception e){\n            e.printStackTrace();\n        } finally {\n            countDownLatch.countDown();\n        }\n    }\n}\n\n\n        ]]></code>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/LockShouldWithTryFinallyRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <test-code>\n        <description>LockShouldWithTryFinallyRule</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>15,20</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.test.p3c;\n\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * @author caikang\n * @date 2019/09/29\n */\npublic class LockTest {\n    private Lock lock = new ReentrantLock();\n\n    public void testLock() {\n        try {\n            lock.lockInterruptibly();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        try {\n            lock.lock();\n            try {\n\n            } finally {\n            }\n        } catch (Exception e) {\n\n        } finally {\n            lock.unlock();\n        }\n    }\n}\n        ]]></code>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/ThreadLocalShouldRemoveRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <test-code>\n        <description>ThreadLocalShouldRemoveRule</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>9,10</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class ThreadLocalTest {\n    private String test;\n    private ThreadLocal<String> local;\n    private static ThreadLocal<String> local2;\n\n    public void remove(){\n        //local.remove();\n        //local2.remove();\n    }\n}\n\n        ]]></code>\n    </test-code>\n\n    <test-code>\n        <description>with remove</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class ThreadLocalTest {\n    private String test;\n    private ThreadLocal<String> local;\n    private static ThreadLocal<String> local2;\n\n    public void remove(){\n        local.remove();\n        local2.remove();\n    }\n}\n        ]]></code>\n    </test-code>\n\n    <test-code>\n        <description>with initial 1</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\n/**\n * @author caikang\n * @date 2017/3/29\n */\npublic class ThreadLocalTest {\n    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {\n        @Override\n        protected DateFormat initialValue() {\n            return new SimpleDateFormat(\"yyyy-MM-dd\");\n        }\n    };\n}\n\n        ]]></code>\n    </test-code>\n\n    <test-code>\n        <description>with initial 2</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\n/**\n * @author caikang\n * @date 2017/3/29\n */\npublic class ThreadLocalTest {\n    private static final ThreadLocal<DateFormat> df = ThreadLocal.withInitial(() -> new SimpleDateFormat(\"yyyy-MM-dd\"));\n}\n\n        ]]></code>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/ThreadPoolCreationRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\t<test-code>\n\t\t<description>Executors.new</description>\n\t\t<expected-problems>5</expected-problems>\n\t\t<expected-linenumbers>9,11,16,17,18</expected-linenumbers>\n\t\t<code><![CDATA[\n\npackage com.alibaba.idea.pmd.test;\n\nimport java.util.concurrent.ExecutorService;\nimport static java.util.concurrent.Executors.newSingleThreadExecutor;\n\n\nimport java.util.concurrent.Executors;\npublic class Executors2Test {\n    private ExecutorService executorService = newSingleThreadExecutor();\n\n    private ExecutorService executorService1 = Executors.newSingleThreadExecutor();\n\n    private ExecutorService executorServic2 = executorService;\n\n    public SimpleDateFormatRule2Test(){\n        executorService1 = newSingleThreadExecutor();\n        newSingleThreadExecutor().submit(() -> System.out.println(\"xxx\"));\n        java.util.concurrent.Executors.newSingleThreadExecutor().submit(() -> {\n\n        });\n    }\n}\n        ]]></code>\n\t</test-code>\n\t<test-code>\n\t\t<description>no Executors</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code><![CDATA[\n\npackage com.alibaba.idea.pmd.test.thread;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author caikang\n * @date 2016/11/17\n */\npublic class ExecutorsTest2 {\n    private void test(){\n        new ThreadPoolExecutor(10,10,100,TimeUnit.MILLISECONDS,new SynchronousQueue<>(),\n                Executors.defaultThreadFactory());\n       ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                new ThreadFactory() {\n                    @Override\n                    public Thread newThread(Runnable r) {\n                        return new Thread();\n                    }\n                }, (r, executor) -> {\n\n                });\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                r -> {\n                    Thread thread1 = new Thread();\n                    thread1.setName(\"xxx\");\n                    return thread1;\n                }, new RejectedExecutionHandler() {\n            @Override\n            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n\n            }\n        });\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());\n    }\n}\n\n        ]]></code>\n\t</test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/concurrent/xml/ThreadShouldSetNameRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <test-code>\n        <description>ThreadShouldSetNameRule</description>\n        <expected-problems>3</expected-problems>\n        <expected-linenumbers>17,19,26</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.idea.pmd.test.thread;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author caikang\n * @date 2016/11/17\n */\npublic class ThreadNameTest implements ThreadFactory{\n\n    private void test(){\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>()\n               , (r, executor) -> System.out.println(\"xxx\"));\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                new RejectedExecutionHandler() {\n                    @Override\n                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n\n                    }\n                });\n        new ThreadPoolExecutor(10,10,100,TimeUnit.MILLISECONDS,new SynchronousQueue<>(),\n                Executors.defaultThreadFactory());\n\n    }\n\n    @Override\n    public Thread newThread(Runnable r) {\n        return null;\n    }\n}\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>right</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>11</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba;\n\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\n\n/**\n * @author caikang\n * @date 2017/03/07\n */\npublic class TestScheduledExecutorService {\n    public static final ScheduledExecutorService EXECUTOR_SERVICE = new ScheduledThreadPoolExecutor(3);\n}\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>right</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\n\n/**\n * @author caikang\n * @date 2017/03/07\n */\npublic class Main {\n\n    public static void main(String[] args) {\n        new ScheduledThreadPoolExecutor(1, (Runnable r) -> {\n            Thread thread = new Thread();\n            thread.setName(\"111\");\n            return thread;\n        });\n    }\n}\n\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>right</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.idea.pmd.test.thread;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author caikang\n * @date 2016/11/17\n */\npublic class ThreadNameTest implements ThreadFactory{\n\n    private void test(){\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),r -> {\n            Thread thread1 = new Thread();\n            thread1.setName(\"xxx\");\n            return thread1;\n        });\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),new ThreadNameTest());\n       ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                new ThreadFactory() {\n                    @Override\n                    public Thread newThread(Runnable r) {\n                        return new Thread();\n                    }\n                }, (r, executor) -> {\n\n                });\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                r -> {\n                    Thread thread1 = new Thread();\n                    thread1.setName(\"xxx\");\n                    return thread1;\n                }, new RejectedExecutionHandler() {\n            @Override\n            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n\n            }\n        });\n        new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),\n                r -> {\n                    Thread thread1 = new Thread();\n                    thread1.setName(\"xxx\");\n                    return thread1;\n                });\n    }\n\n    @Override\n    public Thread newThread(Runnable r) {\n        return null;\n    }\n}\n        ]]></code>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/constant/xml/UndefineMagicConstantRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"constants-ok\"><![CDATA[\n    public class Foo {\n        private final static  String notWarn = \"666l\";\n        }\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>UndefineMagicConstant.</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"constants-ok\"/>\n    </test-code>\n\n    <code-fragment id=\"constants-err\"><![CDATA[\n    public class Foo {\n        private void method() {\n            Integer i = 1;\n            Integer k = 0;\n            Boolean h = false;\n            Long m = 2L;\n            String n = \"\";\n            if (i > 2) {\n            }\n            if (i > 1) {\n            }\n            if (m > 1L) {\n            }\n            if (i != null) {\n            }\n            if (h != false) {\n            }\n            if (n.equals(\"\")) {\n            }\n            for (int j = 0; j < 10; i++) {\n                if (i > 2) {\n\n                }\n                if (i != null) {\n                }\n            }\n            while (k < 1) {\n                if (i > 2) {\n                }\n                k++;\n            }\n        }\n    }\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>UndefineMagicConstant.</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>8,20</expected-linenumbers>\n        <code-ref id=\"constants-err\"/>\n    </test-code>\n\n    <code-fragment id=\"constants-err-2\"><![CDATA[\n\t public class Foo {\n        private void method(String path) {\n\t         if (null == path || !path.startsWith(\"/home/admin/leveldb/\")\n\t                || path.split(\"/\").length <= 5) {\n\t         }\n\t    }\n\t }\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>UndefineMagicConstant.</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>3</expected-linenumbers>\n        <code-ref id=\"constants-err-2\"/>\n    </test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/constant/xml/UpperEllRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"constants-uppercase-L\"><![CDATA[\n\t    public class Foo { \n\t        private final static  String notWarn = \"666l\";    \n            private void processUpperEll(long aLong) {\n                   long good = (4+5*7^66L/7+890) & (88L + 78 * 4);  \n             } \n        } \n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>constants with uppercase L.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"constants-uppercase-L\" />\n\t</test-code>\n\n\t<code-fragment id=\"constants-lowercase-l\"><![CDATA[\n  \t  public class Foo { \n            private static final long IGNORE = 666l + 666L;   \n            private static final Long notWarn = 666L;   \n            private void processUpperEll(long aLong) {\n                long bad = (4+5*7^66l/7+890)  \n                    & (88l + 78 * 4);  \n                long good = (4+5*7^66L/7+890) & (88L + 78 * 4);  \n             } \n        } \n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>constants with lowercase l.</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>2,5,6</expected-linenumbers>\n\t\t<code-ref id=\"constants-lowercase-l\" />\n\t</test-code>\n\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/exception/xml/AvoidReturnInFinallyRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"finally-has-return\">\n        <![CDATA[\n\tpublic class Example {\n\t    public int fn() {\n\t    \ttry {\n\t    \t    return 1;\n\t    \t} finally {\n\t    \t\treturn 0;\n\t    \t}\n\t    }\n\t}\n\t\t]]>\n    </code-fragment>\n    <test-code>\n        <description>finally statement contains return</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>6</expected-linenumbers>\n        <code-ref id=\"finally-has-return\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"finally-has-multi-return\">\n        <![CDATA[\n\tpublic class Example {\n\t    public int fn() {\n\t        int a = 0;\n\t    \ttry {\n\t    \t    a++;\n\t    \t    return 1;\n\t    \t} finally {\n\t    \t\tif (a > 1) {\n\t    \t\t    return a;\n\t    \t\t} else {\n\t    \t\t    return 0;\n\t    \t\t}\n\t    \t}\n\t    }\n\t}\n\t\t]]>\n    </code-fragment>\n    <test-code>\n        <description>finally statement has multiple return</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>9,11</expected-linenumbers>\n        <code-ref id=\"finally-has-multi-return\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"finally-no-return\">\n        <![CDATA[\n\tpublic class Example {\n\t    public int fn() {\n\t        int a = 0;\n\t    \ttry {\n\t    \t    a++;\n\t    \t    return 1;\n\t    \t} finally {\n\t    \t\t// do thing\n\t    \t}\n\t    \treturn 0;\n\t    }\n\t}\n\t\t]]>\n    </code-fragment>\n    <test-code>\n        <description>finally statement contains no return</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"finally-no-return\"/>\n    </test-code>\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/exception/xml/MethodReturnWrapperTypeRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"MethodReturnWrapperTypeRule\">\n        <![CDATA[\npublic class Add{\n    public int add(Integer x, Integer y) {\n        return x+y;\n    }\n    public int add1(Integer x, Integer y) {\n        return new Integer(5);\n    }\n     public int add2(Integer x, Integer y) {\n        return map.get(1);\n    }\n    public int add3(Integer x, Integer y) {\n        Integer z =  new Integer(5);\n        return z;\n    }\n    public String add4(Integer x, Integer y) {\n        Integer z =  new Integer(5);\n        return z;\n    }\n    public boolean testBoolean() {\n        Boolean z =  new Boolean();\n        return z;\n    }\n    public float testFloat() {\n        Float z =  new Float();\n        return z;\n    }\n    public double testDouble() {\n        Double z =  new Double();\n        return z;\n    }\n    public byte testByte() {\n        Byte z =  new Byte();\n        return z;\n    }\n    public short testShort() {\n        Short z =  new Short();\n        return z;\n    }\n    public long testLong() {\n        Long z =  new Long();\n        return z;\n    }\n    public char testCharacter() {\n        Character z =  new Character();\n        return z;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>If the return type is primitive, return a value of wrapper class may cause NullPointerException</description>\n        <expected-problems>8</expected-problems>\n        <expected-linenumbers>11,19,23,27,31,35,39,43</expected-linenumbers>\n        <code-ref id=\"MethodReturnWrapperTypeRule\"/>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/exception/xml/TransactionMustHaveRollbackRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <test-code>\n        <description>TransactionMustHaveRollbackRule</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>17</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.support.ResourceTransactionManager;\nimport org.springframework.transaction.support.SimpleTransactionStatus;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class TestTransactional {\n    private ResourceTransactionManager manager;\n\n    @Transactional\n    @Override\n    public void test(){\n        //manager.rollback(new SimpleTransactionStatus());\n    }\n}\n        ]]></code>\n    </test-code>\n\n    <test-code>\n        <description>readOnly</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.support.ResourceTransactionManager;\nimport org.springframework.transaction.support.SimpleTransactionStatus;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class TestTransactional {\n    private ResourceTransactionManager manager;\n\n    @Transactional(readOnly = true)\n    @Override\n    public void test(){\n        //manager.rollback(new SimpleTransactionStatus());\n    }\n}\n        ]]></code>\n    </test-code>\n\n    <test-code>\n        <description>with rollback</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.support.ResourceTransactionManager;\nimport org.springframework.transaction.support.SimpleTransactionStatus;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class TestTransactional {\n    private ResourceTransactionManager manager;\n\n    @Transactional\n    public void test(){\n        manager.rollback(new SimpleTransactionStatus());\n    }\n}\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>with rollback</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.support.ResourceTransactionManager;\nimport org.springframework.transaction.support.SimpleTransactionStatus;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\npublic class TestTransactional {\n    private ResourceTransactionManager manager;\n\n    @Transactional(rollbackFor = Exception.class)\n    public void test(){\n        //manager.rollback(new SimpleTransactionStatus());\n    }\n}\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>class</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>10</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.support.ResourceTransactionManager;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\n@Transactional\npublic class TestTransactional {\n    private ResourceTransactionManager manager;\n\n    public void test(){\n        //manager.rollback(new SimpleTransactionStatus());\n    }\n}\n        ]]></code>\n    </test-code>\n\n    <test-code>\n        <description>class with rollbackFor</description>\n        <expected-problems>0</expected-problems>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.support.ResourceTransactionManager;\n\n/**\n * @author caikang\n * @date 2017/03/29\n */\n@Transactional(rollbackFor = Exception.class)\npublic class TestTransactional {\n    private ResourceTransactionManager manager;\n\n    public void test(){\n        //manager.rollback(new SimpleTransactionStatus());\n    }\n}\n        ]]></code>\n    </test-code>\n    <test-code>\n        <description>class with rollbackFor</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>10</expected-linenumbers>\n        <code><![CDATA[\npackage com.alibaba.p3c.example.concurrent;\n\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.support.ResourceTransactionManager;\n\n/**\n@author caikang\n@date 2017/03/29\n*/\n@Transactional\npublic class TestTransactional {\n\nprivate ResourceTransactionManager manager;\n\npublic void test(){\n    manager.rollback(new SimpleTransactionStatus());\n}\n}\n        ]]></code>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/xml/AvoidComplexConditionRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"complex-condition\">\n        <![CDATA[\n    public class Example {\n        public int fn1(int a, int b, int c) {\n            if (a == 0 || (b !=0 && c > 0)) {\n                return 1;\n            }\n            return 0;\n        }\n\n        public int fn2(int a, int b, int c) {\n            return (a == 0 || b != 0 && c > 0) ? 1 : 0;\n        }\n\n        public int fn3(int a, int b, int c) {\n            if (a == 0 || b !=0 || c > 0) {\n                return 1;\n            }\n            return 0;\n        }\n\n        public int fn4(int a, int b, int c) {\n            return (a == 0 && b != 0 && c > 0) ? 1 : 0;\n        }\n\n        public int fn5(int a, int b, boolean c) {\n            return (a == 0 && b != 0 && c) ? 1 : 0;\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>complex conditional expression in if condition</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>3,10</expected-linenumbers>\n        <code-ref id=\"complex-condition\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"extract-condition-as-variable\">\n        <![CDATA[\n    public class Example {\n        public int fn3(int a, int b, int c) {\n            boolean flag = (a == 0 || b != 0 && c > 0);\n            return flag ? 1 : 0;\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>complex conditional expression extracted as variable</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"extract-condition-as-variable\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"simple-condition\">\n        <![CDATA[\n    public class Example {\n        public int fn() {\n            List<Integer> ids = new ArrayList<>();\n            if (ids.size() > 0) {\n\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>simple conditional expression</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"simple-condition\"/>\n    </test-code>\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/xml/AvoidNegationOperatorRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"unnecessary-not-expression\">\n        <![CDATA[\n    public class Example {\n        public int foo(int a, int b) {\n            if (!(a > b)) {\n                return -1;\n            }\n            if (!(a == b)) {\n                return -1;\n            }\n            if (!(a != b)) {\n                return -1;\n            }\n            if (!(a > 0 && b > 0)) {\n                return 1;\n            }\n            if (!(a == 0 && b >= 0)) {\n                return 1;\n            }\n            return 0;\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>unnecessary not operator can be removed</description>\n        <expected-problems>3</expected-problems>\n        <expected-linenumbers>3,6,9</expected-linenumbers>\n        <code-ref id=\"unnecessary-not-expression\"/>\n    </test-code>\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/xml/NeedBraceRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"if-no-brace\">\n        <![CDATA[\n\tpublic class Example {\n\t    public void fn() {\n\t    \tint a;\n\t    \tint b;\n\t    \tif (a > 0) b++;\n\t    }\n\t}\n\t\t]]>\n    </code-fragment>\n    <test-code>\n        <description>if statement without {}</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>5</expected-linenumbers>\n        <code-ref id=\"if-no-brace\"/>\n    </test-code>\n\n\t<!-- ====================================================================== -->\n\n    <code-fragment id=\"else-no-brace\">\n        <![CDATA[\n\tpublic class Example {\n\t    public void fn() {\n\t    \tint a = 2;\n\t    \tint b = 4;\n\n\t    \tif (a > 0) b++;\t\t\t// BAD\n\n\t    \tif (a > 0) {\n\t    \t\tb++;\n\t    \t} else if (a > -1) {\n\t    \t\tb++;\n\t    \t} else\n\t    \t\tb--;\t\t\t\t// BAD\n\n\t    \tfor (a = 0; a < 3; a ++) b--;\t// BAD\n\n\t\t\twhile (a > 3) a--;\t\t\t\t// BAD\n\t    }\n\t}\n]]>\n    </code-fragment>\n    <test-code>\n        <description>else,while,for statement without {}</description>\n        <expected-problems>4</expected-problems>\n        <expected-linenumbers>6,13,15,17</expected-linenumbers>\n        <code-ref id=\"else-no-brace\"/>\n    </test-code>\n\n\t<!-- ====================================================================== -->\n\n\t<code-fragment id=\"else-line-no\">\n\t\t<![CDATA[\n\tpublic class Example {\n\t    public void fn() {\n\t    \tint a;\n\t    \tboolean flag;\n\t    \tif (a > 0) {\n\t    \t\t// do nothing\n\t    \t}\n\n\t    \t else\n\n\n\t    \t\tflag = true;\n\t    }\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>figure out else line no</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<!-- else statement line number is not available in AST, so add violation in following statement -->\n\t\t<expected-linenumbers>12</expected-linenumbers>\n\t\t<code-ref id=\"else-line-no\"/>\n\t</test-code>\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/flowcontrol/xml/SwitchStatementRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"switch-no-default-1\">\n        <![CDATA[\n    public class Example {\n        public void fn() {\n            int i;\n            switch (i) {\n                case 0:\n                    break;\n                case 1:\n                    int j;\n                    switch (j) {\n                        case 0:\n                            break;\n                        default:    // nested switch has default blocks\n                            return;\n                    }\n                    break;\n                // missing default statement\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>switch statement in outer class has no default block</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>4</expected-linenumbers>\n        <code-ref id=\"switch-no-default-1\" />\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"switch-no-default-2\">\n        <![CDATA[\n    public class Foo {\n        public void bar() {\n            int i;\n            switch (i) {\n                case 0:\n                    break;\n                case 1:\n                    int j;\n                    switch (j) {\n                        case 0:\n                            break;\n                        // nested switch has no default block\n                    }\n                    break;\n                default:\n                    return;\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>nested switch has no default block</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>9</expected-linenumbers>\n        <code-ref id=\"switch-no-default-2\" />\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"switch-case-no-break\">\n        <![CDATA[\n    public class Foo {\n        public void bar() {\n            int i;\n            switch (i) {\n                case 0:\n                    int j =1;\n                    // missing break,return and continue\n                case 1:\n                    break;\n                case 2:\n                    continue;\n                case 3:        // OK\n                default:\n                    int k = 1;\n                    return;\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>case statement without break</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>4</expected-linenumbers>\n        <code-ref id=\"switch-case-no-break\" />\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"default-no-break\">\n        <![CDATA[\n    public class Foo {\n        public void bar() {\n            int i;\n            switch (i) {\n                case 0:\n                    int j =1;\n                    break;\n                case 1:\n                case 2:\n                    continue;\n                default:    // OK\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>default statement has no break</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"default-no-break\" />\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n\n    <code-fragment id=\"multi-case-no-statement\">\n        <![CDATA[\n    public class Foo {\n        public void bar() {\n            int i;\n            switch (i) {\n                case 0:\n                case 1:\n                case 2:\n                    // do something\n                    break;\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>multiple continuous blank case</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>4</expected-linenumbers>\n        <code-ref id=\"multi-case-no-statement\" />\n    </test-code>\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/AbstractClassShouldStartWithAbstractNamingRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"AbstractNamingRuleStartWithabstract\">\n        <![CDATA[\npublic abstract class abstractNameRuleTest {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>abstract class name should start with Abstract or Base</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>1</expected-linenumbers>\n        <code-ref id=\"AbstractNamingRuleStartWithabstract\" />\n    </test-code>\n\n    <code-fragment id=\"AbstractNamingRuleStartWithAbstract\">\n        <![CDATA[\npublic abstract class AbstractNameRuleTest {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>abstract class name should start with Abstract or Base</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"AbstractNamingRuleStartWithAbstract\" />\n    </test-code>\n\n    <code-fragment id=\"AbstractNamingRuleStartWithBase\">\n        <![CDATA[\npublic abstract class BaseAbstractNameRuleTest {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>abstract class name should start with Abstract or Base</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"AbstractNamingRuleStartWithBase\" />\n    </test-code>\n\n    <code-fragment id=\"AbstractNamingRuleStartWithbase\">\n        <![CDATA[\npublic abstract class baseAbstractNameRuleTest {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>abstract class name should start with Abstract or Base</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>1</expected-linenumbers>\n        <code-ref id=\"AbstractNamingRuleStartWithbase\" />\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/ArrayNamingShouldHaveBracketRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"ArrayTypeStyleTest\">\n        <![CDATA[\n  public class ArrayTypeStyleTest{\n    private String array2[];\n    private String[] array1;\n    public void f(){\n      String[] array3;\n      String array4[];\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>array should be array[]</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>2,6</expected-linenumbers>\n        <code-ref id=\"ArrayTypeStyleTest\" />\n    </test-code>\n\n    <code-fragment id=\"ArrayTypeStyleTest1\">\n        <![CDATA[\n  public class ArrayTypeStyleTest{\n    private String[] array1;\n    public void f(){\n      String[] array2;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>array should be array[]</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"ArrayTypeStyleTest1\" />\n    </test-code>\n\n    <code-fragment id=\"ArrayTypeStyleTest2\">\n        <![CDATA[\n  public class ArrayTypeStyleTest{\n    public void ConfParse(String str){\n        TreeMap<String, String> mapConfKeyValue = new TreeMap<>();\n        String[] params = str.split(\"&\");\n        for (String param : params) {\n            String fields[] = param.split(\"=\");\n            if (fields.length != 2) {\n                continue;\n            }\n            String key = fields[0].trim();\n            String value = fields[1].trim();\n            mapConfKeyValue.put(key, value);\n        }\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>array should be array[]</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>6</expected-linenumbers>\n        <code-ref id=\"ArrayTypeStyleTest2\" />\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/AvoidStartWithDollarAndUnderLineNamingRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"AvoidStartWithDollarAndUnderLine\">\n        <![CDATA[\npublic class AvoidStartWithDollarAndUnderLineNamingRuleTest {\n    private String $1;\n    private String _1;\n    public void $sayHello(){}\n    public void _sayHello(){}\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>name should not be start with $ and _</description>\n        <expected-problems>4</expected-problems>\n        <expected-linenumbers>2,3,4,5</expected-linenumbers>\n        <code-ref id=\"AvoidStartWithDollarAndUnderLine\"></code-ref>\n    </test-code>\n\n    <code-fragment id=\"AvoidStartWithDollarAndUnderLine1\">\n        <![CDATA[\npublic class AvoidStartWithDollarAndUnderLineNamingRuleTest {\n    private String s;\n    public void sayHello(){}\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>name should not be start with $ and _</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"AvoidStartWithDollarAndUnderLine1\" />\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/BooleanPropertyShouldNotStartWithIsRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"boolean-property-in-POJO-class\">\n        <![CDATA[\n  public class BooleanPropertyNamingRuleTestDO{\n    private boolean issuccess;\n    private boolean issuccess1;\n    private boolean success;\n    public void sayHello (int i) {\n     boolean issuccess1;\n     boolean success1;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>issuccess should not contain is</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>2,3</expected-linenumbers>\n        <code-ref id=\"boolean-property-in-POJO-class\" />\n    </test-code>\n\n\n    <code-fragment id=\"boolean-property-in-POJO-class1\">\n        <![CDATA[\n  public class BooleanPropertyNamingRuleTest{\n    private boolean success;\n    public void sayHello (int i) {\n     boolean success1;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>issuccess should not contain is</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"boolean-property-in-POJO-class1\" />\n    </test-code>\n\n    <code-fragment id=\"boolean-property-in-POJO-class2\">\n        <![CDATA[\npublic class ProcessBuilder {\n  public static final boolean isWindows = isWindows();\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>issuccess should not contain is</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"boolean-property-in-POJO-class2\" />\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/ClassNamingShouldBeCamelRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"CamelClassNaming\">\n        <![CDATA[\npublic class CamelClassNameRuleTest {\n    class CamelclassnameRuleTest{}\n    class CamelclassNameRuleTest{}\n    class camelClassNameRuleTest{}\n    class camelClassNameruletest{}\n    class CamelclassNameRuleTestDO{}\n    class CamelclassNameRuleTestDODO{}\n    class CamelclassNameRuleTestdo{}\n    class CamelclassNameRuleTestBO{}\n    class CamelclassNameRuleTestBo{}\n    class CamelclassNameRuleTestbO{}\n    class CamelclassNameRuleTestYunOS{}\n    class CamelclassNameRuleTestyunOS{}\n    class CamelclassNameRuleTestDDO{}\n    class ICamelclassNameRuleTestDO{}\n    class ICamelclassNameRuleTest{}\n    class IDO{}\n    class IAO{}\n    class IpAO{}\n    class CamelclassNameRuleTestAO{}\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Class Name Should Camel</description>\n        <expected-problems>6</expected-problems>\n        <expected-linenumbers>4,5,7,13,14,18</expected-linenumbers>\n        <code-ref id=\"CamelClassNaming\" />\n    </test-code>\n\n\n    <code-fragment id=\"CamelClassNaming1\">\n        <![CDATA[\npublic class CamelClassNameRuleTest {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Class Name Should Camel1</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"CamelClassNaming1\" />\n    </test-code>\n\n    <code-fragment id=\"CamelClassNaming2\">\n        <![CDATA[\npublic class AbstractDAOImpl {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Class Name Should Camel2</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"CamelClassNaming2\" />\n    </test-code>\n\n    <code-fragment id=\"CamelClassNaming3\">\n        <![CDATA[\npublic class AbstractBO {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Class Name Should Camel3</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"CamelClassNaming3\" />\n    </test-code>\n\n    <code-fragment id=\"CamelClassNaming4\">\n        <![CDATA[\npublic class TestBO {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Class Name Should Camel4</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"CamelClassNaming4\" />\n    </test-code>\n\n    <code-fragment id=\"CamelClassNaming5\">\n        <![CDATA[\npublic class RoutingBranchRouteBO extends AbstractBO {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Class Name Should Camel5</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"CamelClassNaming5\" />\n    </test-code>\n    <code-fragment id=\"CamelClassNaming6\">\n        <![CDATA[\npublic class RoutingBranchRoutePO{\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Class Name Should Camel6</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"CamelClassNaming6\" />\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/ConstantFieldShouldBeUpperCaseRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"ConstantFieldNamingRule\">\n    <![CDATA[\n    public class ConstantFieldNameRuleTest {\n    private  static final int MAX = 5;\n    private  static final long serialVersionUID = 1L;\n    //except Log\n    private static final Logger logger = new Logger();\n    //Constant variable names should be written in upper characters separated by underscores\n    private static final boolean success = true;\n    private static final Integer xxxService = 1;\n    private static final Integer xxxxservice = 1;\n       public void f() {\n         int il = 0;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Constant name should be upper case</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>7,9</expected-linenumbers>\n        <code-ref id=\"ConstantFieldNamingRule\" />\n    </test-code>\n\n    <code-fragment id=\"ConstantFieldNamingRule1\">\n        <![CDATA[\n    public class ConstantFieldNameRuleTest {\n    private  static final int MAX = 5;\n    private  static final long serialVersionUID = 1L;\n    //Log除外\n    private static final Logger logger = new Logger();\n    private static final Log log = new Log();\n       public void f() {\n         int il = 0;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Constant name should be upper case</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"ConstantFieldNamingRule1\" />\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/ExceptionClassShouldEndWithExceptionRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"ExceptionNamingRuleTest1\">\n        <![CDATA[\npublic class EndWithExceptionRuleTest extends Exception {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Exception class name should end with Exception</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>1</expected-linenumbers>\n        <code-ref id=\"ExceptionNamingRuleTest1\" />\n    </test-code>\n\n    <code-fragment id=\"ExceptionNamingRuleTest2\">\n        <![CDATA[\npublic class RuleException extends Exception {\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Exception class name should end with Exception</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"ExceptionNamingRuleTest2\" />\n    </test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/LowerCamelCaseVariableNamingRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest\">\n        <![CDATA[\n        public class VariableNameRuleTest {\n    private String abC;\n    private String AbC;\n    private String abCd;\n    private String locationA;\n    private void f(){\n        String s = \"test\";\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>3</expected-linenumbers>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest1\">\n        <![CDATA[\n        public class VariableNameRuleTest {\n    private String abCdeFghKmi123;\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase1</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest1\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest2\">\n        <![CDATA[\npublic interface PluginConstants {\n    String PLUGIN_ID = \"PMDPlugin\";\n     String RULE = \"java/ali-pmd\";\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase2</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest2\" />\n    </test-code>\n\n\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest3\">\n        <![CDATA[\npublic class PluginConstants {\n    String PLUGIN_ID = \"PMDPlugin\";\n    String RULE = \"java/ali-pmd\";\n    private private static final String CONSTANT_RULE = \"constantRuleTest\";\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase3</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>2,3</expected-linenumbers>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest3\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest4\">\n        <![CDATA[\npublic interface BizConstants {\n        interface SDK4cloud {\n        int USER_TYPE_JAQ = 1;\n        int USER_TYPE_ALIYUN = 2;\n        int ACCESS_USAGE_SERVER = 0;\n        int GATEWAY_TYPE_POP = 2;\n        }\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase4</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest4\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest5\">\n        <![CDATA[\n        public class demoTest{\n        public static String ENV_LOCAL = \"local\";\n        public static String ENV_PROJECT = \"project\";\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase5</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest5\" />\n    </test-code>\n\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest6\">\n        <![CDATA[\n        public class FinalVariableTest{\n        public static String ENV_LOCAL = \"local\";\n        public static String ENV_PROJECT = \"project\";\n        private final int MAX_LENGTH =  5;\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase6</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest6\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest7\">\n        <![CDATA[\n     public class MockTest{\n        @Mock\n        void $clinit(){}\n     }   \n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase7</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest7\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest8\">\n        <![CDATA[\n        public @interface TYPE {\n            int DO_NO_THING = 0;\n            int DO_ONE_START_TO_END_ROUTE = 1;\n            int DO_ONE_CAR_TO_START_ROUTE = 2;\n            int DO_TWO_ROUTE = 3;\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase8</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest8\" />\n    </test-code>\n\n    <code-fragment id=\"VariableNamingStartOrEndWithDollarAndUnderLine\">\n        <![CDATA[\n        public class Example {\n            public void test(){\n                String $myName = \"zhangsan\";\n                int _myAge = 18;\n            }\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable Naming Start Or End With Dollar And UnderLine</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"VariableNamingStartOrEndWithDollarAndUnderLine\" />\n    </test-code>\n\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest9\">\n        <![CDATA[\n        public @interface ValueType {\n            int TYPE_NULL = 0;\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase9</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest9\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest10\">\n        <![CDATA[\n         public class Example {\n            public void test(){\n                String myNAME = \"zhangsan\";\n            }\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase10</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>3</expected-linenumbers>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest10\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest11\">\n        <![CDATA[\n         public class Example {\n            public void test(){\n                String myDOList = \"DOList\";\n                String myDTOList = \"DTOList\";\n                String myVOList = \"VOList\";\n                String myDAOList = \"DAOList\";\n                String myBOList = \"BOList\";\n            }\n            public void getScrollX(){}\n            public void getScrollY(){}\n            public void getScrollZ(){}\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase11</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest11\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest12\">\n        <![CDATA[\n         public class Example {\n            public void test(){\n                String myBO = \"myBO\";\n            }\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase12</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest12\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest13\">\n        <![CDATA[\n         public class Example {\n            public void test(){\n                String myUDF = \"myUDF\";\n            }\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase13</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest13\" />\n    </test-code>\n\n    <code-fragment id=\"LowerCamelCaseVariableNamingRuleTest14\">\n        <![CDATA[\n         public class Example {\n            public void test(){\n                String myUDAF = \"myUDAF\";\n            }\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Variable name should be lowerCamelCase14</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"LowerCamelCaseVariableNamingRuleTest14\" />\n    </test-code>\n\n</test-data>\n\n\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/PackageNamingRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"PackageNamingRule\">\n        <![CDATA[\n        // should be lowercase name\n        package com.MyCompany;\n        public class SomeClass {\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Package Name should be lowercase</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>2</expected-linenumbers>\n        <code-ref id=\"PackageNamingRule\" />\n    </test-code>\n\n\n    <code-fragment id=\"PackageNamingRule1\">\n        <![CDATA[\n        // should be lowercase name\n        package com.my.company;\n        public class SomeClass {\n        }\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Package Name should be lowercase</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"PackageNamingRule1\" />\n    </test-code>\n\n\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/ServiceOrDaoClassShouldEndWithImplRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"ServiceClassNamingRule\">\n        <![CDATA[\npublic class ServiceNameRuleTest implements TestDAO{\n    class ServiceNameRuleTest1 implements TestService{\n\n    }\n    class ServiceNameRuleTest2Impl implements TestService{\n\n    }\n    class ServiceNameRuleTest3Impl implements TestDAO{\n\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Service Class Name should be end with Impl</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>1,2</expected-linenumbers>\n        <code-ref id=\"ServiceClassNamingRule\" />\n    </test-code>\n\n\n\n    <code-fragment id=\"ServiceClassNamingRule1\">\n        <![CDATA[\npublic class ServiceNameRuleTestImpl implements TestDAO{\n\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Service Class Name should be end with Impl</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"ServiceClassNamingRule1\" />\n    </test-code>\n\n    <code-fragment id=\"ServiceClassNamingRule2\">\n        <![CDATA[\npublic abstract class ServiceNameRuleTest implements TestDAO{\n\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Service Class Name should be end with Impl</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"ServiceClassNamingRule2\" />\n    </test-code>\n\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/naming/xml/TestClassShouldEndWithTestNamingRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n    <code-fragment id=\"TestClassNameEndWithTest\">\n        <![CDATA[\n        import org.junit.Test;\npublic class TestClassNameRuleTest {\n    @Test\n    public void testCase() {\n\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Test Class Name Should End With Test</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"TestClassNameEndWithTest\" />\n    </test-code>\n\n\n    <code-fragment id=\"TestClassNameNotEndWithTest\">\n        <![CDATA[\n        import org.junit.Test;\npublic class TestClassNameRuleErrorExample {\n    @Test\n    public void testCase() {\n\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Test Class Name Should End With Test</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>2</expected-linenumbers>\n        <code-ref id=\"TestClassNameNotEndWithTest\" />\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/oop/xml/BigDecimalAvoidDoubleConstructorRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"bigdecimal-initialization\">\n        <![CDATA[\n    public class Foo {\n        public void bar() {\n            BigDecimal a = new BigDecimal(0.1);\n            BigDecimal b = new BigDecimal(\"0.1\");\n            BigDecimal c = BigDecimal.valueOf(0.1);\n\n            Double d = Double.parseDouble(\"0.1\");\n            BigDecimal e = new BigDecimal(d);\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>BigDicimal initializer allocation</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>3,8</expected-linenumbers>\n        <code-ref id=\"bigdecimal-initialization\"/>\n    </test-code>\n\n\n    <!-- ====================================================================== -->\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/oop/xml/EqualsAvoidNullRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"argument-is-string-literal\">\n        <![CDATA[\n    public class Foo {\n        private String alias;\n\n        public void bar() {\n            String name;\n            if (name.equals(\"tom\")) {    // BAD\n                return;\n            };\n\n            if (name.toString().equals(\"tom\")) { // BAD\n                return;\n            }\n\n            if (this.alias.equals(\"tom\")) { // BAD\n                return;\n            }\n\n            Integer a;\n            if (a.equals(3)) { // OK, literal number has no equals method\n                return;\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>argument of equals is string literal</description>\n        <expected-problems>3</expected-problems>\n        <expected-linenumbers>6,10,14</expected-linenumbers>\n        <code-ref id=\"argument-is-string-literal\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"argument-is-constant\">\n        <![CDATA[\n    public class Foo {\n        private static final String TOM = \"tom\";\n\n        public void bar() {\n            String label;\n            //\"abc\".equals(label);            // OK\n            //\"abc\".equals(label.toString()); // OK\n            if (label.equals(TOM)) {        // BAD\n                return;\n            };\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>argument of equals is constant</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>8</expected-linenumbers>\n        <code-ref id=\"argument-is-constant\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"both-object-equals\">\n        <![CDATA[\n    public class Foo {\n        public void bar() {\n            String name;\n            String label;\n            if (name.equals(label)) {    // OK\n                return;\n            };\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>non literal with equals</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"both-object-equals\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"equals-in-nested-class\">\n        <![CDATA[\n    public class Foo {\n        public static class Inner1 {\n            public void bar() {\n                String name;\n                if (name.equals(\"\")) {\n                    return;\n                };\n            }\n        }\n        public static class Inner2 {\n            public void bar() {\n                String name;\n                if (name.equals(\"\")) {\n                    return;\n                };\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>multiple nested class</description>\n        <expected-problems>2</expected-problems>\n        <code-ref id=\"equals-in-nested-class\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"caller-is-constant\">\n        <![CDATA[\n    public class Foo {\n        private static final ThreadLocal<Boolean> LOCAL_TEST_FLAG = new ThreadLocal<Boolean>();\n\n        public static boolean isLoadTestFlag() {\n            return Boolean.TRUE.equals(LOCAL_TEST_FLAG.get());\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>caller of equals is constant</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"caller-is-constant\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"string-literal-equals-constant\">\n        <![CDATA[\n    public class Test {\n        private static final String VERSION = System.getProperty(\"v\");\n        public boolean isJava6(){\n            return \"1.6\".equals(VERSION);\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>string literal equals constant</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"string-literal-equals-constant\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"string-literal-equals-literal\">\n        <![CDATA[\n    public class Test {\n        public boolean isJava6(){\n            return \"1.6\".equals(\"1.6\");\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>string literal equals string literal</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"string-literal-equals-literal\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/oop/xml/PojoMustOverrideToStringRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"pojo-not-override-tostring\">\n\t\t<![CDATA[\n\tpublic class FooDO {\n\t\tprivate String tom;\n\n\t\t// BAD, not Override toString()\n\n\t\tprivate static class NestedDTO {\n\t\t\tprivate String tom;\n\t\t\tprivate boolean isBar;\n\n\t\t\t@Override\n\t\t\tpublic String tostring() {\t\t// BAD\n\t\t\t\treturn tom;\n\t\t\t}\n\t\t}\n\n\t\tprivate static class InnerClass {\n\t\t\t// OK\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>POJO not override toString()</description>\n\t\t<expected-problems>2</expected-problems>\n\t\t<expected-linenumbers>1,6</expected-linenumbers>\n\t\t<code-ref id=\"pojo-not-override-tostring\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\n\t<code-fragment id=\"pojo-override-tostring\">\n\t\t<![CDATA[\n\tpublic class FooDO {\n\t\tprivate String tom;\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn tom;\n\t\t}\n\n\t\tprivate static class NestedDTO {\n\t\t\tprivate String tom;\n\t\t\tprivate boolean isBar;\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\treturn super.toString();\n\t\t\t}\n\t\t}\n\n\t\tprivate static class InnerClass {\n\t\t\t// OK\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>POJO already override toString()</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"pojo-override-tostring\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\n\t<code-fragment id=\"lombok-pojo\">\n\t\t<![CDATA[\n\timport lombok.Data;\n\n\t@Data\n\tpublic class FooDO {\n\t\tprivate String tom;\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>lombok generated source not need override toString()</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"lombok-pojo\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\n\t<code-fragment id=\"lombok-pojo-2\">\n\t\t<![CDATA[\n\t@lombok.Data\n\tpublic class FooDO {\n\t\tprivate String tom;\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>lombok generated source not need override toString()</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"lombok-pojo-2\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\n\t<code-fragment id=\"lombok-pojo-3\">\n\t\t<![CDATA[\n\timport lombok.*;\n\t@Data\n\tpublic class FooDO {\n\t\tprivate String tom;\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>import lombok.*</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"lombok-pojo-3\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\n\t<code-fragment id=\"lombok-pojo-4\">\n\t\t<![CDATA[\n\timport lombok.*;\n\t@ToString(callSuper = true)\n\tpublic class FooDO {\n\t\tprivate String tom;\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>use lombok.@ToString annotation</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"lombok-pojo-4\" />\n\t</test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"interface-with-pojo-surfix\">\n        <![CDATA[\n\tpublic interface FooDO {\n\t}\n\t\t]]>\n    </code-fragment>\n    <test-code>\n        <description>interface with POJO surfix</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"interface-with-pojo-surfix\" />\n    </test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/oop/xml/PojoMustUsePrimitiveFieldRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"pojo-field-has-primitive-type\">\n\t\t<![CDATA[\n\tpublic class FooDO {\n\t\tprivate static final int age;\t\t// OK\n\t\tprivate String tom; \t\t\t\t// OK\n\t\tprivate boolean isBar;\t\t\t\t// BAD\n\t\tprivate byte[] buffer;\t\t\t\t// BAD\n\t\tprivate Long pageSize = 20;\t\t\t// OK\n\n\t\tpublic void bar() {\n\t\t\tint pageNo = 1;\n\t\t}\n\n\t\tprivate static class NestedDTO {\n\t\t\tprivate String tom; \t\t\t// OK\n\t\t\tprivate boolean isBar;\t\t\t// BAD\n\t\t}\n\n\t\tprivate static class InnerClass {\n\t\t\tprivate boolean isBar; \t\t\t// OK\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>POJO has primitive type fields</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>4,5,14</expected-linenumbers>\n\t\t<code-ref id=\"pojo-field-has-primitive-type\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/oop/xml/PojoNoDefaultValueRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"pojo-field-has-default-value\">\n\t\t<![CDATA[\n\tpublic class FooDO {\n\t\tprivate static final String HELLO = \"Hello\";\t// OK\n\t\tprivate String tom = \"\"; \t// BAD\n\t\tprivate String jerry;\t\t// OK\n\t\tprivate int pageSize = 20;\t// BAD\n\n\t\tpublic void bar() {\n\t\t\tint pageNo = 1;\n\t\t}\n\n\t\tprivate static class NestedDTO {\n\t\t\tprivate String tom = \"\"; // BAD\n\t\t}\n\n\t\tprivate static class InnerClass {\n\t\t\tprivate String tom = \"\"; // OK\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>POJO has fields with default value</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>3,5,12</expected-linenumbers>\n\t\t<code-ref id=\"pojo-field-has-default-value\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\n\t<code-fragment id=\"not-pojo\">\n\t\t<![CDATA[\n\tpublic class FooPO {\n\t\tprivate static final String HELLO = \"Hello\";\t// OK\n\t\tprivate String tom = \"\"; \t// OK, not POJO\n\t\tprivate String jerry;\t\t// OK\n\t\tprivate int pageSize = 20;\t// OK, not POJO\n\n\t\tpublic void bar() {\n\t\t\tint pageNo = 1;\n\t\t}\n\n\t\tprivate static class NestedDTO {\n\t\t\tprivate String tom = \"\"; // BAD\n\t\t}\n\t\tprivate static class InnerClass {\n\t\t\tprivate String tom = \"\"; // OK\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>non-POJO, inner POJO class</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<code-ref id=\"not-pojo\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\n\t<code-fragment id=\"pojo-feild-exclusion\">\n\t\t<![CDATA[\n\tpublic class FooBO {\n\t\tprivate static final String HELLO = \"Hello\";\t// OK\n\t\tprivate String tom = \"\"; \t// BAD\n\t\tprivate String jerry;\t\t// OK\n\t\tpublic int pageSize = 20;\t// OK,public\n\n\t\tpublic void bar() {\n\t\t\tint pageNo = 1;\n\t\t}\n\n\t\tprivate static class NestedDTO {\n\t\t\tprivate String tom = \"\"; // BAD\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>not check static, transient or public fields</description>\n\t\t<expected-problems>2</expected-problems>\n\t\t<expected-linenumbers>3,12</expected-linenumbers>\n\t\t<code-ref id=\"pojo-feild-exclusion\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/oop/xml/StringConcatRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\t<code-fragment id=\"in-loop-user-plus\">\n\t\t<![CDATA[\n\tpublic class Example {\n\t\tpublic void fn() {\n\t\t\tString url = null;\n\t\t\tfor (int i = 0; i < 10; i ++) {\n\t\t\t\turl = url +\"&i=\" + i ;\n\t\t\t}\n\n\t\t\twhile (url != null) {\n\t\t\t\turl = \"https://\" +\n\t\t\t\t\t\"taobao.com\";\n\t\t\t}\n\n\t\t\tint j = 5;\n\t\t\tdo {\n\t\t\t\turl = \"https://\" +\n\t\t\t\t\t\"tmall.com\";\n\t\t\t\tj--;\n\t\t\t} while (j > 0);\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>concatenate strings with \"+\" in loop</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>5</expected-linenumbers>\n\t\t<code-ref id=\"in-loop-user-plus\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\t<code-fragment id=\"in-loop-user-sb\">\n\t\t<![CDATA[\n\timport java.util.List;\n\timport java.util.ArrayList;\n\n\tpublic class Example {\n\t\tpublic void fn() {\n\t\t\tStringBuilder stringBuilder = new StringBuilder();\n\t\t\tList<String> tags = new ArrayList<String>();\n\t\t\tfor (String tag : tags) {\n\t\t\t\tstringBuilder.append(tag);\n\t\t\t}\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>concatenate strings with StringBuilder in loop</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"in-loop-user-sb\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\t<code-fragment id=\"in-loop-not-assignment\">\n\t\t<![CDATA[\n\timport java.util.List;\n\timport java.util.ArrayList;\n\timport org.slf4j.Logger;\n\timport org.slf4j.LoggerFactory;\n\n\tpublic class Example {\n    \tprivate static final Logger logger = LoggerFactory.getLogger(Example.class);\n\n\t\tpublic void fn() {\n\t\t\tList<String> tags = new ArrayList<String>();\n\t\t\tfor (String tag : tags) {\n\t\t\t\tlogger.info(\"tag=\" + tag);\n\t\t\t}\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>concatenate strings with \"+\" in non-assignment statement</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"in-loop-not-assignment\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\t<code-fragment id=\"assign-variable-out-of-loop\">\n\t\t<![CDATA[\n\timport java.util.List;\n\timport java.util.ArrayList;\n\n\tpublic class Example {\n\t\tpublic void fn() {\n\t\t\tString key = null;\n\t\t\tList<String> tags = new ArrayList<String>();\n\t\t\tfor (String tag : tags) {\n\t\t\t\tkey = key + tag + \"_SURFIX\";\n\t\t\t}\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>concatenate strings with \"+\" in loop, assigned value presents at right side of = </description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>9</expected-linenumbers>\n\t\t<code-ref id=\"assign-variable-out-of-loop\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\t<code-fragment id=\"assign-variable-in-loop\">\n\t\t<![CDATA[\n\timport java.util.List;\n\timport java.util.ArrayList;\n\n\tpublic class Example {\n\t\tpublic void fn() {\n\t\t\tList<String> tags = new ArrayList<String>();\n\t\t\tfor (String tag : tags) {\n\t\t\t    String key = null;\n\t\t\t\tkey = key + tag + \"_SURFIX\";\n\t\t\t}\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>concatenate strings with \"+\", assigned value defined in loop</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"assign-variable-in-loop\" />\n\t</test-code>\n\n\t<!-- ====================================================================== -->\n\t<code-fragment id=\"nested-loop\">\n\t\t<![CDATA[\n\timport java.util.HashMap;\n\timport java.util.Map;\n\n\tpublic class Foo {\n\t\tpublic static Map<String, Map<String, String>> convertRegister(Map<String, Map<String, String>> register) {\n\t\t\tMap<String, Map<String, String>> newRegister = new HashMap<String, Map<String, String>>();\n\t\t\tfor (Map.Entry<String, Map<String, String>> entry : register.entrySet()) {\n\t\t\t\tString serviceName = entry.getKey();\n\t\t\t\tMap<String, String> serviceUrls = entry.getValue();\n\t\t\t\tif (!serviceName.contains(\":\") && !serviceName.contains(\"/\")) {\n\t\t\t\t\tfor (Map.Entry<String, String> entry2 : serviceUrls.entrySet()) {\n\t\t\t\t\t\tString serviceUrl = entry2.getKey();\n\t\t\t\t\t\tString serviceQuery = entry2.getValue();\n\t\t\t\t\t\tMap<String, String> params = new HashMap<>();\n\t\t\t\t\t\tString group = params.get(\"group\");\n\t\t\t\t\t\tString version = params.get(\"version\");\n\t\t\t\t\t\tString name = serviceName;\n\t\t\t\t\t\tif (group != null && group.length() > 0) {\n\t\t\t\t\t\t\tname = group + \"/\" + name;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (version != null && version.length() > 0) {\n\t\t\t\t\t\t\tname = name + \":\" + version;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tMap<String, String> newUrls = newRegister.get(name);\n\t\t\t\t\t\tif (newUrls == null) {\n\t\t\t\t\t\t\tnewUrls = new HashMap<String, String>();\n\t\t\t\t\t\t\tnewRegister.put(name, newUrls);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnewUrls.put(serviceUrl, params.toString());\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tnewRegister.put(serviceName, serviceUrls);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn newRegister;\n\t\t}\n\t}\n\t\t]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>concatenate strings with \"+\" in nested loop</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"nested-loop\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/oop/xml/WrapperTypeEqualityRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"wrap-type-not-use-equal\">\n        <![CDATA[\n    public class Foo {\n        private static final int x = 3;\n        public void bar() {\n            Integer a = 2;\n            int b = 2;\n            Integer c = 3;\n\n            if (a == b) {    // OK\n                // do nothing\n            }\n            if (a == c) {    // BAD\n                // do nothing\n            }\n            if (a != null) {    // OK\n                // do nothing\n            }\n            if (a == -6) {    // OK\n                // do nothing\n            }\n            if (a == x) {    // OK\n                // do nothing\n            }\n            if (a == Integer.MAX_VALUE) {    // BAD\n                // do nothing\n            }\n            // PMD can not resolve type of Inner.FLAG\n            if (a == Inner.FLAG) {\n                // do nothing\n            }\n            // After upgrade pmd version, can resolve\n            if (a == Integer.valueOf(\"2\")) { //BAD\n                // do nothing\n            }\n            if (a == new Integer(\"2\")) {    // BAD\n                // do nothing\n            }\n        }\n\n        private static class Inner {\n            public static final Integer FLAG = 3;\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>compare wrapper type objects without equals</description>\n        <expected-problems>4</expected-problems>\n        <expected-linenumbers>11,23,31,34</expected-linenumbers>\n        <code-ref id=\"wrap-type-not-use-equal\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"wrong-result-fix\">\n        <![CDATA[\n    package com.alibaba.p3c.pmd.lang.java.rule.concurrent;\n\n    import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;\n    import net.sourceforge.pmd.lang.java.ast.ASTName;\n    import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;\n    import net.sourceforge.pmd.lang.java.ast.Token;\n    import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;\n\n    import java.util.HashSet;\n    import java.util.Set;\n    import java.util.concurrent.Executors;\n\n    public class ThreadPoolCreationRule extends AbstractJavaRule {\n\n        private static final String DOT = \".\";\n        private static final String COLON = \";\";\n        private static final String NEW = \"new\";\n        private static final String EXECUTORS_NEW = Executors.class.getSimpleName() + DOT + NEW;\n        private static final String FULL_EXECUTORS_NEW = Executors.class.getName() + DOT + NEW;\n        private static final String BRACKETS = \"()\";\n        private boolean executorsUsed;\n        private Set<String> importedExecutorsMethods = new HashSet<>();\n\n        @Override\n        public Object visit(ASTPrimaryExpression node, Object data) {\n            if (!executorsUsed && importedExecutorsMethods.isEmpty()) {\n                return super.visit(node, data);\n            }\n\n            Token initToken = (Token) node.jjtGetFirstToken();\n            if (!checkInitStatement(initToken)) {\n                addViolation(data, node);\n            }\n            return super.visit(node, data);\n        }\n\n        private boolean checkInitStatement(Token token) {\n            String fullAssignStatement = getFullAssignStatement(token);\n            if (fullAssignStatement.startsWith(EXECUTORS_NEW)) {\n                return false;\n            }\n            if (!fullAssignStatement.startsWith(NEW) && !fullAssignStatement.startsWith(FULL_EXECUTORS_NEW)) {\n                return true;\n            }\n            // in case of lambda\n            int index = fullAssignStatement.indexOf(BRACKETS);\n            if (index == -1) {\n                return true;\n            }\n            fullAssignStatement = fullAssignStatement.substring(0, index);\n\n            // avoid java.util.concurrent.Executors.newxxxx\n            if (importedExecutorsMethods.contains(fullAssignStatement)) {\n                return false;\n            }\n            // static import\n            return !importedExecutorsMethods.contains(Executors.class.getName() + DOT + fullAssignStatement);\n        }\n\n        private String getFullAssignStatement(final Token token) {\n            if (token == null) {\n                return \"\";\n            }\n            StringBuilder sb = new StringBuilder(48);\n            Token next = token;\n            while (next.next != null && !COLON.equals(next.image)) {\n                sb.append(next.image);\n                next = next.next;\n            }\n            return sb.toString();\n        }\n\n        @Override\n        public Object visit(ASTImportDeclaration node, Object data) {\n            ASTName name = node.getFirstChildOfType(ASTName.class);\n            // in case of static import\n            executorsUsed = executorsUsed || name.getType() == Executors.class;\n            if (name.getImage().startsWith(Executors.class.getName() + DOT)) {\n                importedExecutorsMethods.add(name.getImage());\n            }\n            return super.visit(node, data);\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>bugfix</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"wrong-result-fix\"/>\n    </test-code>\n\n    <!-- ====================================================================== -->\n\n    <code-fragment id=\"array-length-equals\">\n        <![CDATA[\n    public class Test {\n        public void foo(){\n            Integer[] a;\n            Integer[] b;\n            if (a.length == b.length) {\n                return;\n            };\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>array length equals</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"array-length-equals\"/>\n    </test-code>\n    <code-fragment id=\"expression-primitive-equals\">\n        <![CDATA[\n    public class Test {\n        public void foo(){\n            int a;\n            if (Integer.parseInt(\"0\") == a) {\n                return;\n            }\n            if (a == Integer.parseInt(\"0\")) {\n                return;\n            }\n\n            String s = \"0\";\n            if (Integer.parseInt(\"0\") == Integer.parseInt(s)) {\n                return;\n            };\n\n            Integer b;\n            if (b == Integer.parseInt(\"0\")) {\n                return;\n            }\n        }\n    }\n        ]]>\n    </code-fragment>\n    <test-code>\n        <description>expression is primitive type</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>17</expected-linenumbers>\n        <code-ref id=\"expression-primitive-equals\"/>\n    </test-code>\n    <!-- ====================================================================== -->\n\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/orm/xml/IbatisMethodQueryForListRule.xml",
    "content": "<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"IbatisMethodQueryForListRule\">\n        <![CDATA[\n      import com.ibatis.sqlmap.client.SqlMapClient;\npublic class IStudentDaoImpl implements IStudentDao {\n\t private static final SqlMapClient sqlMapClient = new SqlMapClient();\n\t private List<Student> students = sqlMapClient.queryForList(\"student\",1,10);\n     public List<Student> queryStudentByName(String name) {\n        List<Student> students = new SqlMapClient().queryForList(\"student\",1,10);\n        return students;\n     }\n     public List<Teacher> queryStudentByName(String name) {\n        List<Teacher> teachers = sqlMapClient.queryForList(\"teacher\",1,10);\n        return teachers;\n     }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>should not use ibatis method queryForList</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>4,10</expected-linenumbers>\n        <code-ref id=\"IbatisMethodQueryForListRule\"/>\n    </test-code>\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/other/java/UseRightCaseForDateFormatRuleExam.java",
    "content": "package com.alibaba.p3c.pmd.lang.java.rule.other.java;\n\nimport java.text.SimpleDateFormat;\n\n\n/**\n * @author huawen.phw\n * @date 2018/2/1\n * Description:\n */\npublic class UseRightCaseForDateFormatRuleExam {\n\n    private static final String PATTERN= \"yyyyMMdd\";\n\n    public void exam1() {\n        SimpleDateFormat format = new SimpleDateFormat(\"YYYYMMDD\"); //vio\n\n        format = new SimpleDateFormat(\"yyyy/MM/dd\");\n\n        format = new SimpleDateFormat(\"yyyy-MM-dd\");\n\n        format = new SimpleDateFormat(\"yyyymmdd\");\n\n        format = new SimpleDateFormat(\"yyyy-MM-DD\");\n\n        format = new SimpleDateFormat(\"YYYY/MM/dd HH:mm:ss\"); //p2 error\n\n        format = new SimpleDateFormat(\"yyyy/MM/dd HH:mm:ss\"); //right\n\n        format = new SimpleDateFormat(\"yy-MM-DD\");\n\n        format = new SimpleDateFormat(\"YY-MM-DD\");//vio\n\n        format = new SimpleDateFormat(\"YY-md\");//vio\n\n        format = new SimpleDateFormat(\"Yy-md\"); //vio\n\n        format = new SimpleDateFormat(\"yyy-md\"); //not checked\n\n        format = new SimpleDateFormat(\"Y-md\"); // not checked\n\n        format = new SimpleDateFormat(\"y-md\"); // not checked\n\n        format = new SimpleDateFormat(\"dd/MM-YYYY\"); //not checked\n\n        exam_2(PATTERN);//can not checked\n\n        exam_2(\"YYYmmDD\");//can not checked\n    }\n\n    public void exam2(String formatStr) {\n        SimpleDateFormat format = new SimpleDateFormat(PATTERN);//can not checked\n\n        format = new SimpleDateFormat(formatStr);//can not checked\n    }\n\n    public  void exam3(){\n    }\n\n\n}"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/other/xml/AvoidApacheBeanUtilsCopyRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"use-apache-beanutils-copy\"><![CDATA[\nimport java.lang.reflect.InvocationTargetException;\nimport org.apache.commons.beanutils.BeanUtils;\npublic class AvoidApacheBeanUtilsCopyRule {\n    public void test(Object a, Object b) throws IllegalAccessException, InvocationTargetException {\n        BeanUtils.copyProperties(a, b);\n    }\n}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Use Apache BeanUtils copy</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>5</expected-linenumbers>\n\t\t<code-ref id=\"use-apache-beanutils-copy\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"use-spring-beanutils-copy\"><![CDATA[\nimport java.lang.reflect.InvocationTargetException;\nimport org.springframework.beans.BeanUtils;\npublic class MyTest {\n    public void test(Object a, Object b) throws IllegalAccessException, InvocationTargetException {\n        BeanUtils.copyProperties(a, b);\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Use Spring BeanUtils copy</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"use-spring-beanutils-copy\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/other/xml/AvoidDoubleOrFloatEqualCompareRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n\t\t   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t   xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"float-value-compare\">\n\t\t<![CDATA[\npublic class Test {\n    public static void main(String[] args) {\n       \tfloat g = 0.7f-0.6f;\n        float h = 0.8f-0.7f;\n        if (g == h) {\n            System.out.println(\"true\");\n        }\n    }\n}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>float value compare</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>5</expected-linenumbers>\n\t\t<code-ref id=\"float-value-compare\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"float-value-compare1\"><![CDATA[\n\t\tpublic class Test {\n\t\t\tpublic void test(float g, float h) {\n\t\t\t\tif (g == h) {\n\t\t\t\t\tSystem.out.println(\"true\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>float value compare</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>3</expected-linenumbers>\n\t\t<code-ref id=\"float-value-compare1\" />\n\t</test-code>\n\n\t<code-fragment id=\"float-value-compare2\"><![CDATA[\n\t\tpublic class Test {\n\t\t\tpublic void test(double g, double h) {\n\t\t\t\tif (g == h) {\n\t\t\t\t\tSystem.out.println(\"true\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>float value compare</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>3</expected-linenumbers>\n\t\t<code-ref id=\"float-value-compare2\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"float-value-compare3\"><![CDATA[\n\t\tpublic class Test {\n\t\t\tpublic static void main(String[] args) {\n\t\t\t\tdouble g = 0.7d-0.6d;\n\t\t\t\tdouble h = 0.8d-0.7d;\n\t\t\t\tif (g == h) {\n\t\t\t\t\tSystem.out.println(\"true\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>float value compare</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>5</expected-linenumbers>\n\t\t<code-ref id=\"float-value-compare3\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"compare\"><![CDATA[\n\t\tpublic class Test {\n\t\t\tpublic static void main(String[] args) {\n\t\t\t\tdouble dis = 1e-6;\n\t\t\t\tdouble d1 = 0.0000001d;\n\t\t\t\tdouble d2 = 0d;\n\t\t\t\tSystem.out.println(Math.abs(d1 - d2) < dis);\n\t\t\t}\n\t\t}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>compare</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"compare\" />\n\t</test-code>\n\n</test-data>"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/other/xml/AvoidMissUseOfMathRandomRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"miss-use-of-math-random\"><![CDATA[\npublic class Test {\n    public static void main( String args[] ){\n        int i = (int)(Math.random() * 10);\n        System.out.println(\"Next int value: \" + i);\n\n        long j = (long)(Math.random() * 250);\n        System.out.println(\"Next long value: \" + j);\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Miss use of Math.random</description>\n        <expected-problems>2</expected-problems>\n        <expected-linenumbers>3,6</expected-linenumbers>\n        <code-ref id=\"miss-use-of-math-random\" />\n    </test-code>\n\n\n    <code-fragment id=\"normal-use-of-math-random\"><![CDATA[\nimport java.util.Random;\npublic class Test {\n    public static void main( String args[] ){\n        double d = Math.random() * 10;\n\n        Random random = new Random();\n        int k = random.nextInt();\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Normal use of Math.random</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"normal-use-of-math-random\" />\n    </test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/other/xml/AvoidNewDateGetTimeRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"use-new-date-get-time\"><![CDATA[\nimport java.util.Date;\npublic class AvoidNewDateGetTimeRule {\n    public void test() {\n        long time = new Date().getTime();\n    }\n}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Use new Date().getTime()</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>4</expected-linenumbers>\n\t\t<code-ref id=\"use-new-date-get-time\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"not-use-new-date-get-time\"><![CDATA[\nimport java.util.Date;\npublic class AvoidNewDateGetTimeRule {\n    public void test() {\n        long time = new Date(123L).getTime();\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Not using newDate().getTime()</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"not-use-new-date-get-time\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/other/xml/AvoidPatternCompileInMethodRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"use-pattern-compile-as-static-field\"><![CDATA[\nimport java.util.regex.Pattern;\npublic class PatternCompile {\n    // precompile regex\n    private static Pattern NUMBER_PATTERN = Pattern.compile(\"[0-9]+\");\n}\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Use Pattern.compile as static field</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"use-pattern-compile-as-static-field\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"use-pattern-compile-in-method-string-literal\"><![CDATA[\nimport java.util.regex.Pattern;\npublic class PatternCompile {\n    public void getNumberPattern() {\n        // Avoid define Pattern.compile in method body\n        Pattern localPattern = Pattern.compile(\"[0-9]+\");\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Use Pattern.compile in method string literal</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>5</expected-linenumbers>\n\t\t<code-ref id=\"use-pattern-compile-in-method-string-literal\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"use-pattern-compile-in-method-not-literal\"><![CDATA[\nimport java.util.regex.Pattern;\npublic class PatternCompile {\n    public void getNumberPattern(String number) {\n        // define Pattern.compile in method body\n        Pattern localPattern = Pattern.compile(number);\n    }\n}\n    ]]>\n\t</code-fragment>\n\t<test-code>\n\t\t<description>Use Pattern.compile in method not literal</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"use-pattern-compile-in-method-not-literal\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/other/xml/MethodTooLongRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"method-equal-to-80-lines\"><![CDATA[\npublic class MethodTooLongRule {\n    @Test\n    public void test() {\n        int i = 1;\n        i = 2;\n        i = 3;\n        i = 4;\n        i = 5;\n        i = 6;\n        i = 7;\n        i = 8;\n        i = 9;\n        i = 10;\n        i = 11;\n        i = 12;\n        i = 13;\n        i = 14;\n        i = 15;\n        i = 16;\n        i = 17;\n        i = 18;\n        i = 19;\n        i = 20;\n        i = 21;\n        i = 22;\n        i = 23;\n        i = 24;\n        i = 25;\n        i = 26;\n        i = 27;\n        i = 28;\n        i = 29;\n        i = 30;\n        i = 31;\n        i = 32;\n        i = 33;\n        i = 34;\n        i = 35;\n        i = 36;\n        i = 37;\n        i = 38;\n        i = 39;\n        i = 40;\n        i = 41;\n        i = 42;\n        i = 43;\n        i = 44;\n        i = 45;\n        i = 46;\n        i = 47;\n        i = 48;\n        i = 49;\n        i = 50;\n        i = 51;\n        i = 52;\n        i = 53;\n        i = 54;\n        i = 55;\n        i = 56;\n        i = 57;\n        i = 58;\n        i = 59;\n        i = 60;\n        i = 61;\n        i = 62;\n        i = 63;\n        i = 64;\n        i = 65;\n        i = 66;\n        i = 67;\n        i = 68;\n        i = 69;\n        i = 70;\n        i = 71;\n        i = 72;\n        i = 73;\n        i = 74;\n        i = 75;\n        i = 76;\n        i = 77;\n        i = 78;\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Method equal to 80 lines</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"method-equal-to-80-lines\" />\n    </test-code>\n\n\n    <code-fragment id=\"method-more-than-80-lines\"><![CDATA[\npublic class MethodTooLongRule {\n    public void test() {\n        int i = 1;\n        i = 2;\n        i = 3;\n        i = 4;\n        i = 5;\n        i = 6;\n        i = 7;\n        i = 8;\n        i = 9;\n        i = 10;\n        i = 11;\n        i = 12;\n        i = 13;\n        i = 14;\n        i = 15;\n        i = 16;\n        i = 17;\n        i = 18;\n        i = 19;\n        i = 20;\n        i = 21;\n        i = 22;\n        i = 23;\n        i = 24;\n        i = 25;\n        i = 26;\n        i = 27;\n        i = 28;\n        i = 29;\n        i = 30;\n        i = 31;\n        i = 32;\n        i = 33;\n        i = 34;\n        i = 35;\n        i = 36;\n        i = 37;\n        i = 38;\n        i = 39;\n        i = 40;\n        i = 41;\n        i = 42;\n        i = 43;\n        i = 44;\n        i = 45;\n        i = 46;\n        i = 47;\n        i = 48;\n        i = 49;\n        i = 50;\n        i = 51;\n        i = 52;\n        i = 53;\n        i = 54;\n        i = 55;\n        i = 56;\n        i = 57;\n        i = 58;\n        i = 59;\n        i = 60;\n        i = 61;\n        i = 62;\n        i = 63;\n        i = 64;\n        i = 65;\n        i = 66;\n        i = 67;\n        i = 68;\n        i = 69;\n        i = 70;\n        i = 71;\n        i = 72;\n        i = 73;\n        i = 74;\n        i = 75;\n        i = 76;\n        i = 77;\n        i = 78;\n        i = 79;\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Method more than 80 lines</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>2</expected-linenumbers>\n        <code-ref id=\"method-more-than-80-lines\" />\n    </test-code>\n\n\n    <code-fragment id=\"method-less-than-80-lines\"><![CDATA[\npublic class MethodTooLongRule {\n    public void test() {\n        int i = 1;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Method less than 80 lines</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"method-less-than-80-lines\" />\n    </test-code>\n\n    <code-fragment id=\"interface-method\"><![CDATA[\ninterface printable{\n    void print();\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Interface method</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"interface-method\" />\n    </test-code>\n\n\n    <code-fragment id=\"method-signature-multi-lines\"><![CDATA[\npublic class MethodTooLongRule {\n    public\n    void\n    test() {\n        int i = 1;\n        i = 2;\n        i = 3;\n        i = 4;\n        i = 5;\n        i = 6;\n        i = 7;\n        i = 8;\n        i = 9;\n        i = 10;\n        i = 11;\n        i = 12;\n        i = 13;\n        i = 14;\n        i = 15;\n        i = 16;\n        i = 17;\n        i = 18;\n        i = 19;\n        i = 20;\n        i = 21;\n        i = 22;\n        i = 23;\n        i = 24;\n        i = 25;\n        i = 26;\n        i = 27;\n        i = 28;\n        i = 29;\n        i = 30;\n        i = 31;\n        i = 32;\n        i = 33;\n        i = 34;\n        i = 35;\n        i = 36;\n        i = 37;\n        i = 38;\n        i = 39;\n        i = 40;\n        i = 41;\n        i = 42;\n        i = 43;\n        i = 44;\n        i = 45;\n        i = 46;\n        i = 47;\n        i = 48;\n        i = 49;\n        i = 50;\n        i = 51;\n        i = 52;\n        i = 53;\n        i = 54;\n        i = 55;\n        i = 56;\n        i = 57;\n        i = 58;\n        i = 59;\n        i = 60;\n        i = 61;\n        i = 62;\n        i = 63;\n        i = 64;\n        i = 65;\n        i = 66;\n        i = 67;\n        i = 68;\n        i = 69;\n        i = 70;\n        i = 71;\n        i = 72;\n        i = 73;\n        i = 74;\n        i = 75;\n        i = 76;\n        i = 77;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Method signature multi lines</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>4</expected-linenumbers>\n        <code-ref id=\"method-signature-multi-lines\" />\n    </test-code>\n\n\n    <code-fragment id=\"method-signature-with-annotation-multi-lines\"><![CDATA[\npublic class MethodTooLongRule {\n    @Test public\n    void\n    test() {\n        int i = 1;\n        i = 2;\n        i = 3;\n        i = 4;\n        i = 5;\n        i = 6;\n        i = 7;\n        i = 8;\n        i = 9;\n        i = 10;\n        i = 11;\n        i = 12;\n        i = 13;\n        i = 14;\n        i = 15;\n        i = 16;\n        i = 17;\n        i = 18;\n        i = 19;\n        i = 20;\n        i = 21;\n        i = 22;\n        i = 23;\n        i = 24;\n        i = 25;\n        i = 26;\n        i = 27;\n        i = 28;\n        i = 29;\n        i = 30;\n        i = 31;\n        i = 32;\n        i = 33;\n        i = 34;\n        i = 35;\n        i = 36;\n        i = 37;\n        i = 38;\n        i = 39;\n        i = 40;\n        i = 41;\n        i = 42;\n        i = 43;\n        i = 44;\n        i = 45;\n        i = 46;\n        i = 47;\n        i = 48;\n        i = 49;\n        i = 50;\n        i = 51;\n        i = 52;\n        i = 53;\n        i = 54;\n        i = 55;\n        i = 56;\n        i = 57;\n        i = 58;\n        i = 59;\n        i = 60;\n        i = 61;\n        i = 62;\n        i = 63;\n        i = 64;\n        i = 65;\n        i = 66;\n        i = 67;\n        i = 68;\n        i = 69;\n        i = 70;\n        i = 71;\n        i = 72;\n        i = 73;\n        i = 74;\n        i = 75;\n        i = 76;\n        i = 77;\n    }\n}\n    ]]>\n    </code-fragment>\n    <test-code>\n        <description>Method signature with annotation multi lines</description>\n        <expected-problems>1</expected-problems>\n        <expected-linenumbers>4</expected-linenumbers>\n        <code-ref id=\"method-signature-with-annotation-multi-lines\" />\n    </test-code>\n\n    <code-fragment id=\"method-equal-to-80-lines-with-formal-comment\"><![CDATA[\npublic class MethodTooLongRule {\n    @Test\n    public void test() {\n        /**\n         * a java doc comment\n         */\n        int i = 1;\n        i = 2;\n        i = 3;\n        /**\n         * another java doc comment\n         */\n        i = 4;\n        i = 5;\n        i = 6;\n        i = 7;\n        i = 8;\n        i = 9;\n        i = 10;\n        i = 11;\n        i = 12;\n        i = 13;\n        i = 14;\n        i = 15;\n        i = 16;\n        i = 17;\n        i = 18;\n        i = 19;\n        i = 20;\n        i = 21;\n        i = 22;\n        i = 23;\n        i = 24;\n        i = 25;\n        i = 26;\n        i = 27;\n        i = 28;\n        i = 29;\n        i = 30;\n        i = 31;\n        i = 32;\n        i = 33;\n        i = 34;\n        i = 35;\n        i = 36;\n        i = 37;\n        i = 38;\n        i = 39;\n        i = 40;\n        i = 41;\n        i = 42;\n        i = 43;\n        i = 44;\n        i = 45;\n        i = 46;\n        i = 47;\n        i = 48;\n        i = 49;\n        i = 50;\n        i = 51;\n        i = 52;\n        i = 53;\n        i = 54;\n        i = 55;\n        i = 56;\n        i = 57;\n        i = 58;\n        i = 59;\n        i = 60;\n        i = 61;\n        i = 62;\n        i = 63;\n        i = 64;\n        i = 65;\n        i = 66;\n        i = 67;\n        i = 68;\n        i = 69;\n        i = 70;\n        i = 71;\n        i = 72;\n        i = 73;\n        i = 74;\n        i = 75;\n        i = 76;\n        i = 77;\n        i = 78;\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Method equal to 80 lines with formal comment</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"method-equal-to-80-lines-with-formal-comment\" />\n    </test-code>\n\n\n    <code-fragment id=\"method-equal-to-80-lines-with-multi-line-comment\"><![CDATA[\npublic class MethodTooLongRule {\n    @Test\n    public void test() {\n        /* test */\n        int i = 1;\n        /* test\n         test\n         test */\n        i = 2;\n        i = 3;\n        i = 4;\n        i = 5;\n        i = 6;\n        i = 7;\n        i = 8;\n        i = 9;\n        i = 10;\n        i = 11;\n        i = 12;\n        i = 13;\n        i = 14;\n        i = 15;\n        i = 16;\n        i = 17;\n        i = 18;\n        i = 19;\n        i = 20;\n        i = 21;\n        i = 22;\n        i = 23;\n        i = 24;\n        i = 25;\n        i = 26;\n        i = 27;\n        i = 28;\n        i = 29;\n        i = 30;\n        i = 31;\n        i = 32;\n        i = 33;\n        i = 34;\n        i = 35;\n        i = 36;\n        i = 37;\n        i = 38;\n        i = 39;\n        i = 40;\n        i = 41;\n        i = 42;\n        i = 43;\n        i = 44;\n        i = 45;\n        i = 46;\n        i = 47;\n        i = 48;\n        i = 49;\n        i = 50;\n        i = 51;\n        i = 52;\n        i = 53;\n        i = 54;\n        i = 55;\n        i = 56;\n        i = 57;\n        i = 58;\n        i = 59;\n        i = 60;\n        i = 61;\n        i = 62;\n        i = 63;\n        i = 64;\n        i = 65;\n        i = 66;\n        i = 67;\n        i = 68;\n        i = 69;\n        i = 70;\n        i = 71;\n        i = 72;\n        i = 73;\n        i = 74;\n        i = 75;\n        i = 76;\n        i = 77;\n        i = 78;\n        /* test */\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Method equal to 80 lines with multi-line comment</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"method-equal-to-80-lines-with-multi-line-comment\" />\n    </test-code>\n\n    <code-fragment id=\"method-equal-to-80-lines-with-single-line-comment\"><![CDATA[\npublic class MethodTooLongRule {\n    @Test\n    public void test() {\n        // test\n        int i = 1;\n        // test\n        i = 2;\n        i = 3;\n        i = 4;\n        i = 5;\n        i = 6;\n        i = 7;\n        i = 8;\n        i = 9;\n        i = 10;\n        i = 11;\n        i = 12;\n        i = 13;\n        i = 14;\n        i = 15;\n        i = 16;\n        i = 17;\n        i = 18;\n        i = 19;\n        i = 20;\n        i = 21;\n        i = 22;\n        i = 23;\n        i = 24;\n        i = 25;\n        i = 26;\n        i = 27;\n        i = 28;\n        i = 29;\n        i = 30;\n        i = 31;\n        i = 32;\n        i = 33;\n        i = 34;\n        i = 35;\n        i = 36;\n        i = 37;\n        i = 38;\n        i = 39;\n        i = 40;\n        i = 41;\n        i = 42;\n        i = 43;\n        i = 44;\n        i = 45;\n        i = 46;\n        i = 47;\n        i = 48;\n        i = 49;\n        i = 50;\n        i = 51;\n        i = 52;\n        i = 53;\n        i = 54;\n        i = 55;\n        i = 56;\n        i = 57;\n        i = 58;\n        i = 59;\n        i = 60;\n        i = 61;\n        i = 62;\n        i = 63;\n        i = 64;\n        i = 65;\n        i = 66;\n        i = 67;\n        i = 68;\n        i = 69;\n        i = 70;\n        i = 71;\n        i = 72;\n        i = 73;\n        i = 74;\n        i = 75;\n        i = 76;\n        i = 77;\n        i = 78;\n        // test\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Method equal to 80 lines with single-line comment</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"method-equal-to-80-lines-with-single-line-comment\" />\n    </test-code>\n\n    <code-fragment id=\"method-equal-to-80-lines-with-comment-after-expression\"><![CDATA[\npublic class MethodTooLongRule {\n    @Test\n    public void test() { // test\n        int i = 1; // test\n        i = 2;\n        i = 3;\n        i = 4; // test\n        i = 5;\n        i = 6;\n        i = 7;\n        i = 8;\n        i = 9;\n        i = 10;\n        i = 11;\n        i = 12;\n        i = 13;\n        i = 14;\n        i = 15;\n        i = 16;\n        i = 17;\n        i = 18;\n        i = 19;\n        i = 20;\n        i = 21;\n        i = 22;\n        i = 23;\n        i = 24;\n        i = 25;\n        i = 26;\n        i = 27;\n        i = 28;\n        i = 29;\n        i = 30;\n        i = 31;\n        i = 32;\n        i = 33;\n        i = 34;\n        i = 35;\n        i = 36;\n        i = 37;\n        i = 38;\n        i = 39;\n        i = 40;\n        i = 41;\n        i = 42;\n        i = 43;\n        i = 44;\n        i = 45;\n        i = 46;\n        i = 47;\n        i = 48;\n        i = 49;\n        i = 50;\n        i = 51;\n        i = 52;\n        i = 53;\n        i = 54;\n        i = 55;\n        i = 56;\n        i = 57;\n        i = 58;\n        i = 59;\n        i = 60;\n        i = 61;\n        i = 62;\n        i = 63;\n        i = 64;\n        i = 65;\n        i = 66;\n        i = 67;\n        i = 68;\n        i = 69;\n        i = 70;\n        i = 71;\n        i = 72;\n        i = 73;\n        i = 74;\n        i = 75;\n        i = 76;\n        i = 77;\n        i = 78; // test\n    }\n}\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>Method equal to 80 lines with comment after expression</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"method-equal-to-80-lines-with-comment-after-expression\" />\n    </test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/other/xml/UseRightCaseForDateFormatRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"use-right-case-for-date-format\"><![CDATA[\n\t\timport java.text.SimpleDateFormat;\n\t\tclass DateFormatTest {\n        public void test(){\n            SimpleDateFormat format = new SimpleDateFormat(\"YYYYMMDD\"); //vio\n            format = new SimpleDateFormat(\"yyyy/MM/dd\");\n            format = new SimpleDateFormat(\"yyyy-MM-dd\");\n            format = new SimpleDateFormat(\"yyyymmdd\");\n            format = new SimpleDateFormat(\"yyyy-MM-DD\");\n            format = new SimpleDateFormat(\"yy-MM-DD\");\n            format = new SimpleDateFormat(\"YY-MM-DD\");\n            format = new SimpleDateFormat(\"YYmd\");\n            format = new SimpleDateFormat(\"YYYY-M-d\");\n            format = new SimpleDateFormat(\"YYYY-dd\");\n\n        }\n    }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Use right case to format date</description>\n\t\t<expected-problems>5</expected-problems>\n\t\t<expected-linenumbers>4,10,11,12,13</expected-linenumbers>\n\t\t<code-ref id=\"use-right-case-for-date-format\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/set/xml/ClassCastExceptionWithSubListToArrayListRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"sets-ok\"><![CDATA[\n\t    public class Foo {\n            private void method() {\n              List<String> list = new ArrayList<String>();\n             }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-ClassCastExceptionWithSubListToArrayListRule-ok.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"sets-ok\" />\n\t</test-code>\n\n\t<code-fragment id=\"sets-warn\"><![CDATA[\n  \t  public class Foo {\n            private void method(long aLong) {\n               List<String> list = new ArrayList<String>();\n               list.add(\"22\");\n               List<String> test = (ArrayList<String>) list.subList(0, 1);\n             }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-ClassCastExceptionWithSubListToArrayListRule-warn.</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>5</expected-linenumbers>\n\t\t<code-ref id=\"sets-warn\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/set/xml/ClassCastExceptionWithToArrayRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"sets-ClassCastExceptionWithToArray-ok\"><![CDATA[\n\t    public class Foo {\n            private void method(long aLong) {\n              Integer[] b = (Integer [])c.toArray(new Integer[c.size()]);\n             }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-ClassCastExceptionWithToArray-ok.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"sets-ClassCastExceptionWithToArray-ok\" />\n\t</test-code>\n\n\t<code-fragment id=\"sets-ClassCastExceptionWithToArray-warn\"><![CDATA[\n  \t  public class Foo {\n            private void method(long aLong) {\n              Integer[] a = (Integer [])c.toArray();\n             }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-ClassCastExceptionWithToArray-warn.</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>3</expected-linenumbers>\n\t\t<code-ref id=\"sets-ClassCastExceptionWithToArray-warn\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/set/xml/CollectionInitShouldAssignCapacityRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"sets-CollectionInitShouldAssignCapacityRule-ok\"><![CDATA[\n\t    public class Foo {\n\t    \tMap<String,  String> map = new HashMap<String,  String>();\n            private void method(long aLong) {\n               Map<String,  String> map2 = new HashMap<String,  String>(16);\n               Map<String,  String> map3 = new ConcurrentHashMap<String,  String>(16);\n               List<String> originList = new ArrayList<String>(2048);\n            }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-CollectionInitShouldAssignCapacityRule-ok.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"sets-CollectionInitShouldAssignCapacityRule-ok\" />\n\t</test-code>\n\n\t<code-fragment id=\"sets-CollectionInitShouldAssignCapacityRule-warn\"><![CDATA[\n  \t  public class Foo {\n           private void method1() {\n\t\t       Map<String,  String> map = new HashMap<String,  String>();\n\t\t       Map<String,  String> map3 = new ConcurrentHashMap<String,  String>();\n           }\n      }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-CollectionInitShouldAssignCapacityRule-warn.</description>\n\t\t<expected-problems>2</expected-problems>\n\t\t<expected-linenumbers>3,4</expected-linenumbers>\n\t\t<code-ref id=\"sets-CollectionInitShouldAssignCapacityRule-warn\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/set/xml/ConcurrentExceptionWithModifyOriginSubListRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"sets-ok\"><![CDATA[\n\t    public class Foo {\n            private void method() {\n              List<String> originList = new ArrayList<String>();\n              originList.add(\"22\");\n              List<String> subList = originList.subList(0, 1);\n             }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-ConcurrentExceptionWithModifyOriginSubListRule-ok.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"sets-ok\" />\n\t</test-code>\n\n\t<code-fragment id=\"sets-warn\"><![CDATA[\n  \t  public class Foo {\n            private void method(long aLong) {\n                List<String> originList = new ArrayList<String>();\n                originList.add(\"22\");\n                List<String> subList = originList.subList(0, 1);\n                originList.add(\"22\");\n                originList.remove(\"22\");\n                originList.clear();\n             }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-ConcurrentExceptionWithModifyOriginSubListRule-warn.</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>6,7,8</expected-linenumbers>\n\t\t<code-ref id=\"sets-warn\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/set/xml/DontModifyInForeachCircleRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\t<code-fragment id=\"sets-ok\"><![CDATA[\n\t    public class Foo {\n            private void method() {\n               List<String> originList = new ArrayList<String>();\n               originList.add(\"22\");\n               for (String item : originList) {\n\n               }\n               originList.add(\"bb\");\n             }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-ConcurrentExceptionWithModifyOriginSubListRule-ok.</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"sets-ok\" />\n\t</test-code>\n\n\t<code-fragment id=\"sets-warn\"><![CDATA[\n  \t  public class Foo {\n            private void method(long aLong) {\n                List<String> originList = new ArrayList<String>();\n                originList.add(\"22\");\n                for (String item : originList) {\n                     originList.add(\"bb\");\n                     originList.remove(\"cc\");\n                     originList.clear();\n                }\n             }\n        }\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>sets-ConcurrentExceptionWithModifyOriginSubListRule-warn.</description>\n\t\t<expected-problems>3</expected-problems>\n\t\t<expected-linenumbers>6,7,8</expected-linenumbers>\n\t\t<code-ref id=\"sets-warn\" />\n\t</test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/java/rule/set/xml/UnsupportedExceptionWithModifyAsListRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n    <code-fragment id=\"sets-UnsupportedExceptionWithModifyAsListRule-ok\"><![CDATA[\n    public class Foo {\n        private void method(long aLong) {\n            List<String> t   = Arrays.asList(\"a\",\"b\",\"c\");\n        }\n    }\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>sets-UnsupportedExceptionWithModifyAsListRule-ok.</description>\n        <expected-problems>0</expected-problems>\n        <code-ref id=\"sets-UnsupportedExceptionWithModifyAsListRule-ok\"/>\n    </test-code>\n\n    <code-fragment id=\"sets-UnsupportedExceptionWithModifyAsListRule-warn\"><![CDATA[\n    public class Foo {\n        private void method1() {\n            if (true) {\n                List<String> list = Arrays.asList(\"a\", \"b\", \"c\");\n                list.add(\"d\");\n                list.remove(\"22\");\n                list.clear();\n            }\n            List<String> list = new ArrayList<String>();\n            list.add(\"b\");\n            list.remove(\"b\");\n        }\n\n        private void method2() {\n            if (true) {\n                List<String> list = Arrays.asList(\"a\", \"b\", \"c\");\n                list.add(\"d\");\n            }\n            List<String> list = new ArrayList<String>();\n            list.add(\"b\");\n        }\n    }\n    ]]>\n    </code-fragment>\n\n    <test-code>\n        <description>sets-UnsupportedExceptionWithModifyAsListRule-warn.</description>\n        <expected-problems>4</expected-problems>\n        <expected-linenumbers>5,6,7,17</expected-linenumbers>\n        <code-ref id=\"sets-UnsupportedExceptionWithModifyAsListRule-warn\"/>\n    </test-code>\n\n</test-data>\n"
  },
  {
    "path": "p3c-pmd/src/test/resources/com/alibaba/p3c/pmd/lang/vm/rule/other/xml/UseQuietReferenceNotationRule.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test-data xmlns=\"http://pmd.sourceforge.net/rule-tests\"\n           xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n           xsi:schemaLocation=\"http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd\">\n\n\n\t<code-fragment id=\"use-quiet-reference-notation\"><![CDATA[\n<input type=\"text\" name=\"email\" value=\"$!email\"/>\n<input type=\"text\" name=\"email\" value=\"$!{email}\"/>\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Use quiet reference notation</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"use-quiet-reference-notation\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"not-use-quiet-reference-notation\"><![CDATA[\n<input type=\"text\" name=\"email\" value=\"$email\"/>\n<input type=\"text\" name=\"email\" value=\"${email}\"/>\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Not use quiet reference notation</description>\n\t\t<expected-problems>2</expected-problems>\n\t\t<expected-linenumbers>1,2</expected-linenumbers>\n\t\t<code-ref id=\"not-use-quiet-reference-notation\" />\n\t</test-code>\n\n\t<code-fragment id=\"set-directives-is-not-considered\"><![CDATA[\n#set( $email = \"email\" )\n#set( ${email} = \"email\" )\n#if( $foo )\n  <strong>Velocity!</strong>\n#end\n<ul>\n#foreach( $product in $allProducts )\n    <li>$product</li>\n#end\n</ul>\n#include( \"greetings.txt\", $seasonalstock )\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>SetDirectives is not considered</description>\n\t\t<expected-problems>1</expected-problems>\n\t\t<expected-linenumbers>8</expected-linenumbers>\n\t\t<code-ref id=\"set-directives-is-not-considered\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"macro-directives-is-not-considered\"><![CDATA[\n#macro( tablerows $color $somelist )\n\t#foreach( $something in $somelist )\n\t\t<tr><td bgcolor=$color>$something</td></tr>\n\t#end\n#end\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Macro is not considered</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"macro-directives-is-not-considered\" />\n\t</test-code>\n\n\n\t<code-fragment id=\"reference-in-parentheses-is-not-considered\"><![CDATA[\n<td >\n     $!timezone.toLocal($currentDate,null,\"Asia/Shanghai\")\n</td>\n    ]]>\n\t</code-fragment>\n\n\t<test-code>\n\t\t<description>Reference in parentheses is not considered</description>\n\t\t<expected-problems>0</expected-problems>\n\t\t<code-ref id=\"reference-in-parentheses-is-not-considered\" />\n\t</test-code>\n</test-data>\n"
  }
]