gongluzhen 2 лет назад
Родитель
Сommit
2ac5cb4d19
100 измененных файлов с 6213 добавлено и 0 удалено
  1. BIN
      环境配置/技术规范/Java开发手册(正式版).pdf
  2. 95 0
      环境配置/技术规范/p3c/.gitignore
  3. 5 0
      环境配置/技术规范/p3c/README.md
  4. 97 0
      环境配置/技术规范/p3c/eclipse-plugin/.gitignore
  5. 31 0
      环境配置/技术规范/p3c/eclipse-plugin/README.md
  6. 63 0
      环境配置/技术规范/p3c/eclipse-plugin/README_cn.md
  7. 7 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/build.properties
  8. 26 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/feature.properties
  9. 46 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/feature.xml
  10. 13 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/pom.xml
  11. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/smartfox.png
  12. 59 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/META-INF/MANIFEST.MF
  13. 14 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/build.properties
  14. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/actions/clear.gif
  15. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/actions/clear.png
  16. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/actions/quickfixBulb.png
  17. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/actions/rules.png
  18. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/ali-ide-run.png
  19. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/language.png
  20. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/blocker.gif
  21. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/class_obj.png
  22. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/critical.gif
  23. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/major.png
  24. BIN
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/smartfox_logo.png
  25. 153 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/plugin.xml
  26. 124 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/pom.xml
  27. 119 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/QuickFix.kt
  28. 141 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/SmartfoxActivator.kt
  29. 105 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/handler/CodeAnalysisHandler.kt
  30. 52 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/handler/SwitchLanguageHandler.kt
  31. 133 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/job/CodeAnalysis.kt
  32. 34 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/job/P3cMutex.kt
  33. 37 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/message/P3cBundle.kt
  34. 35 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/RulePriority.kt
  35. 185 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AbstractEclipseRule.kt
  36. 110 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AvoidAccessStaticViaInstanceRule.kt
  37. 107 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AvoidUseDeprecationRule.kt
  38. 132 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/MapOrSetKeyShouldOverrideHashCodeEqualsRule.kt
  39. 84 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/MissingOverrideAnnotationRule.kt
  40. 36 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/AllRulesPreferencePage.kt
  41. 49 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/AllRulesView.kt
  42. 68 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultTreeContentProvider.kt
  43. 65 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultTreeLabelProvider.kt
  44. 249 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultView.kt
  45. 103 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResults.kt
  46. 114 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/QuickFixAction.kt
  47. 83 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/RuleDetailComposite.kt
  48. 92 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/RuleDetailView.kt
  49. 86 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/Violations.kt
  50. 20 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/BasicLineStyleListener.kt
  51. 158 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/ContentBuilder.kt
  52. 19 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/FontBuilder.kt
  53. 54 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/StringArranger.kt
  54. 275 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/StyleExtractor.kt
  55. 37 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/SyntaxData.kt
  56. 94 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/SyntaxManager.kt
  57. 361 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/util/CleanUps.kt
  58. 135 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/util/MarkerUtil.kt
  59. 23 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/messages/P3cBundle.xml
  60. 25 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/messages/P3cBundle_en.xml
  61. 17 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/rulesets/java/ali-pmd.xml
  62. 42 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/rulesets/java/ali-ruleOnEclipse.xml
  63. 8 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/syntax/java.properties
  64. 10 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.updatesite/category.xml
  65. 13 0
      环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.updatesite/pom.xml
  66. BIN
      环境配置/技术规范/p3c/eclipse-plugin/doc/images/analyze_result.png
  67. BIN
      环境配置/技术规范/p3c/eclipse-plugin/doc/images/eclipse_analyze.png
  68. BIN
      环境配置/技术规范/p3c/eclipse-plugin/doc/images/eclipse_switch_language.png
  69. BIN
      环境配置/技术规范/p3c/eclipse-plugin/doc/images/install.png
  70. 198 0
      环境配置/技术规范/p3c/eclipse-plugin/pom.xml
  71. 94 0
      环境配置/技术规范/p3c/idea-plugin/.gitignore
  72. 78 0
      环境配置/技术规范/p3c/idea-plugin/README.md
  73. 119 0
      环境配置/技术规范/p3c/idea-plugin/README_cn.md
  74. 38 0
      环境配置/技术规范/p3c/idea-plugin/build.gradle
  75. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/analyze.png
  76. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/analyze_before_checkin.png
  77. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/change_name.png
  78. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/inspection.png
  79. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/inspection_result.png
  80. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/inspection_setting.png
  81. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/install_1.png
  82. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/install_2.png
  83. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/normal_view.png
  84. BIN
      环境配置/技术规范/p3c/idea-plugin/doc/images/switch_language.png
  85. 8 0
      环境配置/技术规范/p3c/idea-plugin/gradle.properties
  86. BIN
      环境配置/技术规范/p3c/idea-plugin/gradle/wrapper/gradle-wrapper.jar
  87. 6 0
      环境配置/技术规范/p3c/idea-plugin/gradle/wrapper/gradle-wrapper.properties
  88. 172 0
      环境配置/技术规范/p3c/idea-plugin/gradlew
  89. 84 0
      环境配置/技术规范/p3c/idea-plugin/gradlew.bat
  90. 107 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/build.gradle
  91. 38 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/java/icons/P3cIcons.java
  92. 209 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/AliInspectionAction.kt
  93. 273 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/PmdGlobalInspectionContextImpl.kt
  94. 51 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/SwitchLanguageAction.kt
  95. 59 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/ToggleProjectInspectionAction.kt
  96. 116 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/compatible/inspection/InspectionProfileService.kt
  97. 67 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/compatible/inspection/Inspections.kt
  98. 150 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/component/AliProjectComponent.kt
  99. 35 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/component/CommonSettingsApplicationComponent.kt
  100. 68 0
      环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/config/P3cConfig.kt

BIN
环境配置/技术规范/Java开发手册(正式版).pdf


+ 95 - 0
环境配置/技术规范/p3c/.gitignore

@@ -0,0 +1,95 @@
+# Gradle
+build
+.gradle
+
+testdata/
+# Java gitignore #
+.class
+.log
+
+# Package Files #
+
+*.war
+*.ear
+
+#hsf files
+configuration
+
+# maven gitignore#
+target/**
+
+.svn/
+
+# intelliJ.gitignore #
+.idea
+*.iml
+*.ipr
+*.iws
+
+
+# Eclipse git ignore#
+*.pydevproject
+.project
+.metadata
+bin/**
+*/bin/**
+tmp/**
+tmp/**/*
+configuration/**
+*.tmp
+*.bak
+*.orig
+*.swp
+*~.nib
+.classpath
+.settings/
+.loadpath
+.fileTable*
+.cache
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+#log
+*.log
+*.log.*
+
+# Windows Thumbs.db
+*.db
+
+# OSX
+.DS_Store
+
+# sass gitignore#
+.sass-cache
+.idea
+
+# tcc_coverage
+coverage.ec
+
+
+
+config.client.*
+
+temp/
+*.pid
+*.orig
+
+hsf.configuration/
+
+# code coverage report
+*.ec
+
+#hsf test
+*.instance
+out
+!/p3c-idea/src/main/kotlin/com/alibaba/smartfox/work/tools/aone/ui/AoneBranchView.kt

Разница между файлами не показана из-за своего большого размера
+ 5 - 0
环境配置/技术规范/p3c/README.md


+ 97 - 0
环境配置/技术规范/p3c/eclipse-plugin/.gitignore

@@ -0,0 +1,97 @@
+# Gradle
+build
+.gradle
+
+testdata/
+# Java gitignore #
+.class
+.log
+
+# Package Files #
+
+*.war
+*.ear
+*.gradle
+
+#hsf files
+configuration
+
+# maven gitignore#
+target/**
+
+.svn/
+
+# intelliJ.gitignore #
+.idea
+*.iml
+*.ipr
+*.iws
+*.bat
+
+# Eclipse git ignore#
+*.pydevproject
+.project
+.metadata
+bin/**
+*/bin/**
+tmp/**
+tmp/**/*
+configuration/**
+*.tmp
+*.bak
+*.orig
+*.swp
+*~.nib
+.classpath
+.settings/
+.loadpath
+.fileTable*
+.cache
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+#log
+*.log
+*.log.*
+
+# Windows Thumbs.db
+*.db
+
+# OSX
+.DS_Store
+
+# sass gitignore#
+.sass-cache
+.idea
+
+# tcc_coverage
+coverage.ec
+
+
+
+config.client.*
+
+temp/
+*.pid
+*.orig
+
+hsf.configuration/
+
+# code coverage report
+*.ec
+
+#hsf test
+*.instance
+**/target
+.pmd
+**/.pmd

+ 31 - 0
环境配置/技术规范/p3c/eclipse-plugin/README.md

@@ -0,0 +1,31 @@
+# Eclipse Plugin
+---
+## <font color="green">Prepare</font>
+- Eclipse Juno+ 
+- maven3.+
+- JDK 1.7+
+
+## <font color="green">Build</font>
+```
+mvn -U clean install
+```
+## [中文使用手册](README_cn.md)
+## <font color="green">Install</font>
+1. <font color="blue">Help >> Install New Software
+then enter this update site URL [https://p3c.alibaba.com/plugin/eclipse/update](https://p3c.alibaba.com/plugin/eclipse/update)</font>
+
+![Install Plugin](doc/images/install.png) 
+
+2. <font color="blue">Follow the wizard, restart Eclipse to take effect after install success.</font>
+
+## <font color="green">Use</font>
+1. <font color="blue">Switch language</font>
+
+	![Switch language](doc/images/eclipse_switch_language.png) 
+
+2. <font color="blue">Code Analyze </font>
+
+  ![Analyze](doc/images/eclipse_analyze.png) 
+  
+  ![Analyze](doc/images/analyze_result.png) 
+    

+ 63 - 0
环境配置/技术规范/p3c/eclipse-plugin/README_cn.md

@@ -0,0 +1,63 @@
+> 首先非常感谢大家对插件的支持与意见,Eclipse的功能相对来说比较简单,希望有更多的同学加入进来一起完善。
+
+## 插件安装
+环境:JDK1.8,Eclipse4+。有同学遇到过这样的情况,安装插件重启后,发现没有对应的菜单项,从日志上也看不到相关的异常信息,最后把JDK从1.6升级到1.8解决问题。
+
+Help -> Install New Software...
+
+![](https://gw.alicdn.com/tfscom/TB1LOyPifJNTKJjSspoXXc6mpXa.png)
+
+输入Update Site地址:https://p3c.alibaba.com/plugin/eclipse/update 回车,然后勾选Ali-CodeAnalysis,再一直点Next Next...按提示走下去就好。 然后就是提示重启了,安装完毕。
+
+![](https://gw.alicdn.com/tfscom/TB1Ud5kifBNTKJjSszcXXbO2VXa.png)
+
+注意:有同学反映插件扫描会触发很多 "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)
+
+
+## 插件使用
+
+目前插件实现了开发手册中的53条规则,大部分基于PMD实现,其中有4条规则基于Eclipse实现,支持4条规则的QuickFix功能。
+
+	* 所有的覆写方法,必须加@Override注解, 
+ 	* if/for/while/switch/do等保留字与左右括号之间都必须加空格,
+ 	* long或者Long初始赋值时,必须使用大写的L,不能是小写的l)
+ 	* Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals。
+ 	
+目前不支持代码实时检测,需要手动触发,希望更多的人加入进来一起把咱们的插件做得越来越好,尽量提升研发的使用体验。
+
+   
+### 代码扫描
+可以通过右键菜单、Toolbar按钮两种方式手动触发代码检测。同时结果面板中可以对部分实现了QuickFix功能的规则进行快速修复。
+
+#### 触发扫描
+在当前编辑的文件中点击右键,可以在弹出的菜单中触发对该文件的检测。
+
+![](https://gw.alicdn.com/tfscom/TB1XGo8iPihSKJjy0FeXXbJtpXa.png)
+
+
+在左侧的Project目录树种点击右键,可以触发对整个工程或者选择的某个目录、文件进行检测。 
+
+![](https://gw.alicdn.com/tfscom/TB18UsJi2NZWeJjSZFpXXXjBFXa.png)
+
+   
+也可以通过Toolbar中的按钮来触发检测,目前Toolbar的按钮触发的检测范围与您IDE当时的焦点有关,如当前编辑的文件或者是Project目录树选中的项,是不是感觉与右键菜单的检测范围类似呢。 
+
+  ![](https://gw.alicdn.com/tfscom/TB1vt1oifBNTKJjSszcXXbO2VXa.png)
+
+   
+#### 扫描结果  
+简洁的结果面板,按规则等级分类,等级->规则->文件->违规项。同时还提供一个查看规则详情的界面。
+
+清除结果标记更方便,支持上面提到的4条规则QuickFix。
+
+![](https://gw.alicdn.com/tfscom/TB1_uFJi6ihSKJjy0FlXXadEXXa.png)
+
+#### 查看所有规则
+![](https://gw.alicdn.com/tfscom/TB1UNTnmYsTMeJjSszhXXcGCFXa.png)
+![](https://gw.alicdn.com/tfscom/TB1_rf7sOAKL1JjSZFoXXagCFXa.png)
+
+#### 国际化
+
+![](https://gw.alicdn.com/tfscom/TB1KsyYsiFTMKJjSZFAXXckJpXa.png) 
+
+![](https://gw.alicdn.com/tfscom/TB19bzdm3oQMeJjy1XaXXcSsFXa.png)

+ 7 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/build.properties

@@ -0,0 +1,7 @@
+bin.includes = feature.xml,\
+               feature.properties,\
+               smartfox.png
+src.includes = build.properties,\
+               feature.properties,\
+               feature.xml,\
+               smartfox.png

+ 26 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/feature.properties

@@ -0,0 +1,26 @@
+feature.label = Ali-CodeAnalysis
+feature.provider_name = Alibaba
+feature.update_site_name = Alibaba IDE Portal
+
+description.text =  Alibaba Java Coding Guidelines
+description.url = https://github.com/alibaba/p3c
+
+copyright.text =\
+Copyright 2017 Alibaba Java Coding Guidelines
+
+license.url = https://github.com/alibaba/p3c
+license.text =\
+ 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\
+

+ 46 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/feature.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+        id="com.alibaba.smartfox.eclipse.feature"
+        label="%feature.label"
+        version="2.0.1.qualifier"
+        provider-name="%feature.provider_name"
+        plugin="com.alibaba.smartfox.eclipse.plugin"
+        image="smartfox.png">
+
+    <description url="%description.url">
+        Alibaba Java Coding Guidelines
+    </description>
+
+    <copyright>
+        %copyright.text
+    </copyright>
+
+    <license url="%license.url">
+        %license.text
+    </license>
+
+    <url>
+        <update label="%feature.update_site_name" url="https://p3c.alibaba.com/plugin/eclipse/update"/>
+    </url>
+
+    <requires>
+        <import plugin="org.eclipse.ui"/>
+        <import plugin="org.eclipse.core.runtime"/>
+        <import plugin="org.eclipse.jdt.core"/>
+        <import plugin="org.eclipse.ui.ide"/>
+        <import plugin="org.eclipse.ui.views"/>
+        <import plugin="org.eclipse.core.resources"/>
+        <import plugin="org.eclipse.jface.text"/>
+        <import plugin="org.eclipse.ui.workbench.texteditor"/>
+        <import plugin="org.eclipse.ltk.core.refactoring"/>
+        <import plugin="org.eclipse.jdt.ui"/>
+        <import plugin="org.eclipse.core.filebuffers"/>
+    </requires>
+
+    <plugin
+            id="com.alibaba.smartfox.eclipse.plugin"
+            download-size="0"
+            install-size="0"
+            version="0.0.0"/>
+
+</feature>

+ 13 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/pom.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.alibaba.smartfox.eclipse</groupId>
+    <artifactId>smartfox-eclipse</artifactId>
+    <version>2.0.1-SNAPSHOT</version>
+  </parent>
+  <artifactId>com.alibaba.smartfox.eclipse.feature</artifactId>
+  <packaging>eclipse-feature</packaging>
+  <inceptionYear>2017</inceptionYear>
+</project>

BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.feature/smartfox.png


+ 59 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/META-INF/MANIFEST.MF

@@ -0,0 +1,59 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: com.alibaba.smartfox.eclipse.plugin
+Bundle-SymbolicName: com.alibaba.smartfox.eclipse.plugin;singleton:=true
+Bundle-Version: 2.0.1.qualifier
+Bundle-Activator: com.alibaba.smartfox.eclipse.SmartfoxActivator
+Bundle-Vendor: Alibaba
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.jdt.core,
+ org.eclipse.ui.ide,
+ org.eclipse.ui.views,
+ org.eclipse.core.resources,
+ org.eclipse.jface.text,
+ org.eclipse.ui.workbench.texteditor,
+ org.eclipse.ltk.core.refactoring,
+ org.eclipse.jdt.ui,
+ org.eclipse.core.filebuffers,
+ org.eclipse.equinox.p2.core,
+ org.eclipse.equinox.p2.engine,
+ org.eclipse.equinox.p2.operations,
+ org.eclipse.equinox.p2.metadata.repository,
+ org.eclipse.equinox.p2.ui,
+ org.eclipse.equinox.p2.metadata
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Bundle-ClassPath: target/lib/antlr-runtime.jar,
+ target/lib/antlr4-runtime.jar,
+ target/lib/asm.jar,
+ target/lib/commons-io.jar,
+ target/lib/commons-lang3.jar,
+ target/lib/gson.jar,
+ target/lib/javacc.jar,
+ target/lib/jaxen.jar,
+ target/lib/jcommander.jar,
+ target/lib/log4j.jar,
+ target/lib/pmd-core.jar,
+ target/lib/pmd-java.jar,
+ target/lib/pmd-javascript.jar,
+ target/lib/pmd-vm.jar,
+ target/lib/rhino.jar,
+ target/lib/saxon-dom.jar,
+ target/lib/saxon.jar,
+ target/lib/p3c-pmd.jar,
+ target/lib/kotlin-stdlib.jar,
+  target/lib/statistics-client.jar,
+    target/lib/guava.jar,
+ target/classes/,
+ .
+Bundle-Localization: plugin
+Export-Package: com.alibaba.smartfox.eclipse,
+ com.alibaba.smartfox.eclipse.handler,
+ com.alibaba.smartfox.eclipse.job,
+ com.alibaba.smartfox.eclipse.marker,
+ com.alibaba.smartfox.eclipse.pmd,
+ com.alibaba.smartfox.eclipse.pmd.rule,
+ com.alibaba.smartfox.eclipse.ui,
+ com.alibaba.smartfox.eclipse.ui.pmd,
+ com.alibaba.smartfox.eclipse.util

+ 14 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/build.properties

@@ -0,0 +1,14 @@
+bin.includes = .,\
+               META-INF/,\
+               plugin.xml,\
+               icons/,\
+               target/lib/
+src.includes = icons/,\
+               META-INF/,\
+               plugin.xml,\
+               messages.properties,\
+               target/lib/,\
+               src/main/kotlin,\
+               pom.xml
+source.. = src/main/java/,src/main/resources
+output.. = target/classes/

BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/actions/clear.gif


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/actions/clear.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/actions/quickfixBulb.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/actions/rules.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/ali-ide-run.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/language.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/blocker.gif


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/class_obj.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/critical.gif


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/major.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/icons/view/smartfox_logo.png


+ 153 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/plugin.xml

@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+    <extension
+          id="SmartFoxViews"
+          name="SmartFoxViews"
+          point="org.eclipse.ui.views">
+        <category
+                name="SmartFoxViews"
+                id="com.alibaba.smartfox.eclipse.ui">
+        </category>
+        <view
+                name="P3C Results"
+                allowMultiple="false"
+                icon="icons/view/smartfox_logo.png"
+                category="com.alibaba.smartfox.eclipse.ui"
+                class="com.alibaba.smartfox.eclipse.ui.InspectionResultView"
+                id="com.alibaba.smartfox.eclipse.ui.InspectionResultView">
+        </view>
+        <view
+                name="Rule Detail"
+                allowMultiple="false"
+                icon="icons/view/smartfox_logo.png"
+                category="com.alibaba.smartfox.eclipse.ui"
+                class="com.alibaba.smartfox.eclipse.ui.RuleDetailView"
+                id="com.alibaba.smartfox.eclipse.ui.RuleDetailView">
+        </view>
+        <stickyView
+                location="LEFT"
+                id="com.alibaba.smartfox.eclipse.ui.RuleDetailView">
+        </stickyView>
+    </extension>
+
+    <extension point="org.eclipse.core.expressions.definitions">
+        <definition id="when.alibaba.analysis.is.active">
+            <or>
+                <with variable="activePartId">
+                    <equals
+                            value="org.eclipse.jdt.ui.PackageExplorer">
+                    </equals>
+                </with>
+                <with variable="activePartId">
+                    <equals
+                            value="org.eclipse.ui.navigator.ProjectExplorer">
+                    </equals>
+                </with>
+                <with variable="activeSite">
+                    <adapt
+                            type="org.eclipse.ui.IEditorSite">
+                    </adapt>
+
+                </with>
+            </or>
+
+        </definition>
+    </extension>
+    <extension
+            point="org.eclipse.ui.commands">
+        <category
+                description="Alibaba Code Analysis"
+                id="alibaba.ui.commands"
+                name="Alibaba Command">
+        </category>
+        <command
+                categoryId="alibaba.ui.commands"
+                description="Alibaba Code Analysis"
+                id="com.alibaba.smartfox.eclipse.command.analysis"
+                name="Alibaba Code Analysis"/>
+        <command
+                categoryId="alibaba.ui.commands"
+                description="Alibaba Code Analysis"
+                id="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler"
+                name="Switch Language"/>
+    </extension>
+    <extension
+            point="org.eclipse.ui.bindings">
+        <key
+                commandId="com.alibaba.smartfox.eclipse.command.analysis"
+                contextId="org.eclipse.ui.contexts.window"
+                schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
+                sequence="Ctrl+Shift+Alt+J">
+        </key>
+    </extension>
+    <extension
+            point="org.eclipse.ui.handlers">
+        <handler
+                class="com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler"
+                commandId="com.alibaba.smartfox.eclipse.command.analysis">
+            <enabledWhen>
+                <reference
+                        definitionId="when.alibaba.analysis.is.active">
+                </reference>
+            </enabledWhen>
+        </handler>
+        <handler
+                class="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler"
+                commandId="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler">
+        </handler>
+    </extension>
+    <extension point="org.eclipse.ui.menus">
+        <menuContribution allPopups="false"
+                          locationURI="popup:org.eclipse.ui.popup.any">
+            <command
+                    commandId="com.alibaba.smartfox.eclipse.command.analysis"
+                    icon="icons/ali-ide-run.png"
+                    label="Alibaba Code Guidelines"
+                    style="push">
+                <visibleWhen
+                        checkEnabled="false">
+                    <reference definitionId="when.alibaba.analysis.is.active"/>
+                </visibleWhen>
+            </command>
+        </menuContribution>
+        <menuContribution
+                allPopups="false"
+                locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions">
+            <toolbar
+                    id="com.alibaba.smartfox.eclipse.plugin.toolbar3">
+                <command
+                        commandId="com.alibaba.smartfox.eclipse.command.analysis"
+                        icon="icons/ali-ide-run.png"
+                        label="Alibaba Code Guidelines"
+                        style="push"
+                        tooltip="Alibaba Code Guidelines">
+                </command>
+                <command
+                        commandId="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler"
+                        icon="icons/language.png"
+                        label="Switch Language"
+                        style="push"
+                        tooltip="Switch Language">
+                </command>
+            </toolbar>
+        </menuContribution>
+    </extension>
+    <extension
+            id="p3cMarker"
+            name="P3C Violations"
+            point="org.eclipse.core.resources.markers">
+        <persistent value="false"/>
+        <super type="org.eclipse.core.resources.problemmarker"/>
+    </extension>
+    <extension point="org.eclipse.ui.ide.markerResolution">
+        <markerResolutionGenerator
+                markerType="com.alibaba.smartfox.eclipse.plugin.p3cMarker"
+                class="com.alibaba.smartfox.eclipse.QuickFixGenerator"/>
+    </extension>
+    <extension point="org.eclipse.ui.preferencePages">
+        <page name="Alibaba Code Analysis"
+              class="com.alibaba.smartfox.eclipse.ui.AllRulesPreferencePage"
+              id="com.alibaba.smartfox.eclipse.ui.AllRulesPreferencePage"/>
+    </extension>
+</plugin>

+ 124 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/pom.xml

@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.alibaba.smartfox.eclipse</groupId>
+    <artifactId>smartfox-eclipse</artifactId>
+    <version>2.0.1-SNAPSHOT</version>
+  </parent>
+  <artifactId>com.alibaba.smartfox.eclipse.plugin</artifactId>
+  <packaging>eclipse-plugin</packaging>
+  <inceptionYear>2017</inceptionYear>
+  <properties>
+    <kotlin.compiler.incremental>false</kotlin.compiler.incremental>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.17</version>
+    </dependency>
+    <dependency>
+      <groupId>com.alibaba.p3c</groupId>
+      <artifactId>p3c-pmd</artifactId>
+      <version>2.0.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jetbrains.kotlin</groupId>
+      <artifactId>kotlin-stdlib-jdk8</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>20.0</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <sourceDirectory>src/main/kotlin</sourceDirectory>
+    <plugins>
+      <plugin>
+        <groupId>org.jetbrains.kotlin</groupId>
+        <artifactId>kotlin-maven-plugin</artifactId>
+        <version>${kotlin.version}</version>
+
+        <executions>
+          <execution>
+            <id>compile</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+          </execution>
+
+          <execution>
+            <id>test-compile</id>
+            <phase>test-compile</phase>
+            <goals>
+              <goal>test-compile</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>3.1.1</version>
+        <configuration>
+          <stripVersion>true</stripVersion>
+          <prependGroupId>false</prependGroupId>
+          <outputDirectory>${project.build.directory}/lib</outputDirectory>
+          <!-- exclude the apex (transitive) dependencies - we use the shaded
+              version instead -->
+          <excludeGroupIds>p2.eclipse-plugin,apex</excludeGroupIds>
+          <excludeArtifactIds>com.alibaba.smartfox.eclipse.plugin
+          </excludeArtifactIds>
+          <useRepositoryLayout>false</useRepositoryLayout>
+        </configuration>
+        <executions>
+          <execution>
+            <id>get-dependencies</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+    <pluginManagement>
+      <plugins>
+        <!--This plugin's configuration is used to store Eclipse m2e settings
+            only. It has no influence on the Maven build itself. -->
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>
+                      org.apache.maven.plugins
+                    </groupId>
+                    <artifactId>
+                      maven-dependency-plugin
+                    </artifactId>
+                    <versionRange>[0,)</versionRange>
+                    <goals>
+                      <goal>copy-dependencies</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore></ignore>
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>

+ 119 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/QuickFix.kt

@@ -0,0 +1,119 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse
+
+import com.alibaba.p3c.pmd.lang.java.rule.constant.UpperEllRule
+import com.alibaba.p3c.pmd.lang.java.rule.oop.EqualsAvoidNullRule
+import com.alibaba.smartfox.eclipse.ui.InspectionResults
+import com.alibaba.smartfox.eclipse.util.getRule
+import com.google.common.io.Files
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.resources.IMarker
+import org.eclipse.core.runtime.NullProgressMonitor
+import org.eclipse.ltk.core.refactoring.TextFileChange
+import org.eclipse.text.edits.ReplaceEdit
+import org.eclipse.ui.IMarkerResolution
+import org.eclipse.ui.IMarkerResolutionGenerator
+import java.nio.charset.Charset
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/14
+ */
+class QuickFixGenerator : IMarkerResolutionGenerator {
+    override fun getResolutions(marker: IMarker): Array<IMarkerResolution> {
+        if (!marker.exists()) {
+            return emptyArray()
+        }
+        val rule = marker.getRule()
+        val quickFix = quickFixes[rule.name] ?: return emptyArray()
+        return arrayOf(quickFix)
+    }
+
+    companion object {
+        val quickFixes = mapOf(UpperEllRule::class.java.simpleName to UpperEllQuickFix,
+                EqualsAvoidNullRule::class.java.simpleName to EqualsAvoidNullQuickFix)
+    }
+}
+
+interface RunWithoutViewRefresh : IMarkerResolution {
+    fun run(marker: IMarker, refresh: Boolean)
+
+    override fun run(marker: IMarker) {
+        run(marker, true)
+    }
+}
+
+abstract class BaseQuickFix : RunWithoutViewRefresh {
+    override fun run(marker: IMarker, refresh: Boolean) {
+        if (!marker.exists()) {
+            return
+        }
+        val file = marker.resource as IFile
+        doRun(marker, file)
+        marker.delete()
+        if (refresh) {
+            InspectionResults.removeMarker(marker)
+        }
+    }
+
+    abstract fun doRun(marker: IMarker, file: IFile)
+}
+
+object UpperEllQuickFix : BaseQuickFix() {
+    override fun doRun(marker: IMarker, file: IFile) {
+        val offset = marker.getAttribute(IMarker.CHAR_START, 0)
+        val end = marker.getAttribute(IMarker.CHAR_END, 0)
+        val content = Files.toString(file.rawLocation.toFile(), Charset.forName(file.charset))
+        val replaceString = content.substring(offset, end + 1).replace("l", "L")
+        val edit = ReplaceEdit(offset, replaceString.length, replaceString)
+        val change = TextFileChange("", file)
+        change.edit = edit
+        change.perform(NullProgressMonitor())
+    }
+
+    override fun getLabel(): String {
+        return "Replace 'l' to 'L'."
+    }
+
+}
+
+object EqualsAvoidNullQuickFix : BaseQuickFix() {
+    val equalsName = ".equals("
+
+    override fun doRun(marker: IMarker, file: IFile) {
+        val offset = marker.getAttribute(IMarker.CHAR_START, 0)
+        val end = marker.getAttribute(IMarker.CHAR_END, 0)
+        val content = Files.toString(file.rawLocation.toFile(), Charset.forName(file.charset))
+        val string = content.substring(offset, end)
+        val list = string.split(equalsName).filterNotNull()
+        if (list.size != 2) {
+            return
+        }
+        val replace = "${list[1].substringBeforeLast(')')}$equalsName${list[0]})"
+        val edit = ReplaceEdit(offset, string.length, replace)
+        val change = TextFileChange("", file)
+        change.edit = edit
+        change.perform(NullProgressMonitor())
+    }
+
+    override fun getLabel(): String {
+        return "Flip equals."
+    }
+
+}

+ 141 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/SmartfoxActivator.kt

@@ -0,0 +1,141 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse
+
+import com.alibaba.p3c.pmd.I18nResources
+import net.sourceforge.pmd.Rule
+import net.sourceforge.pmd.RuleSetFactory
+import net.sourceforge.pmd.RuleSets
+import org.apache.log4j.Logger
+import org.eclipse.core.runtime.IStatus
+import org.eclipse.core.runtime.Status
+import org.eclipse.jface.dialogs.MessageDialog
+import org.eclipse.jface.resource.ImageDescriptor
+import org.eclipse.swt.graphics.Image
+import org.eclipse.swt.widgets.Display
+import org.eclipse.ui.plugin.AbstractUIPlugin
+import org.osgi.framework.BundleContext
+import java.util.Locale
+
+/**
+ * @author caikang
+ * @date 2017/06/14
+ */
+class SmartfoxActivator : AbstractUIPlugin() {
+
+    init {
+        aDefault = this
+    }
+
+    private val logger = Logger.getLogger(javaClass)!!
+    lateinit var ruleSets: RuleSets
+    private val localeKey = "p3c.locale"
+
+    lateinit var ruleMap: Map<String, Rule>
+
+    @Throws(Exception::class) override fun start(context: BundleContext) {
+        super.start(context)
+        I18nResources.changeLanguage(locale)
+        ruleSets = createRuleSets()
+        ruleMap = ruleSets.allRules.associateBy {
+            it.name
+        }
+    }
+
+    @Throws(Exception::class) override fun stop(context: BundleContext?) {
+        aDefault = null
+        super.stop(context)
+    }
+
+
+    fun getImage(key: String, iconPath: String = key): Image {
+        val registry = imageRegistry
+        var image: Image? = registry.get(key)
+        if (image == null) {
+            val descriptor = getImageDescriptor(iconPath)
+            registry.put(key, descriptor)
+            image = registry.get(key)
+        }
+
+        return image!!
+    }
+
+    val locale: String
+        get() {
+            val language = preferenceStore.getString(localeKey)
+            if (language.isNullOrBlank()) {
+                val lang = Locale.getDefault().language
+                return if (lang != Locale.ENGLISH.language && lang != Locale.CHINESE.language) {
+                    Locale.ENGLISH.language
+                } else Locale.getDefault().language
+            }
+
+            return language
+        }
+
+    fun toggleLocale() {
+        val lang = if (Locale.ENGLISH.language == locale) Locale.CHINESE.language else Locale.ENGLISH.language
+        preferenceStore.setValue(localeKey, lang)
+    }
+
+    fun getRule(rule: String): Rule {
+        return ruleMap[rule]!!
+    }
+
+    fun showError(message: String, t: Throwable) {
+        logError(message, t)
+        Display.getDefault().syncExec {
+            MessageDialog.openError(Display.getCurrent().activeShell, "错误", message + "\n" + t.toString())
+        }
+    }
+
+    fun logError(message: String, t: Throwable) {
+        log.log(Status(IStatus.ERROR, bundle.symbolicName, 0, message + t.message, t))
+        logger.error(message, t)
+    }
+
+    fun logError(status: IStatus) {
+        log.log(status)
+        logger.error(status.message, status.exception)
+    }
+
+    fun logInformation(message: String) {
+        log.log(Status(IStatus.INFO, bundle.symbolicName, 0, message, null))
+    }
+
+    fun logWarn(message: String) {
+        log.log(Status(IStatus.WARNING, bundle.symbolicName, 0, message, null))
+    }
+
+    companion object {
+        // The plug-in ID
+        val PLUGIN_ID = "com.alibaba.smartfox.eclipse.plugin"
+
+        var aDefault: SmartfoxActivator? = null
+            private set
+
+        val instance: SmartfoxActivator get() = aDefault!!
+
+        fun getImageDescriptor(path: String): ImageDescriptor {
+            return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path)
+        }
+
+        fun createRuleSets(): RuleSets {
+            val ruleSetFactory = RuleSetFactory()
+            return ruleSetFactory.createRuleSets("java-ali-pmd,vm-ali-other")
+        }
+    }
+}

+ 105 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/handler/CodeAnalysisHandler.kt

@@ -0,0 +1,105 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.handler
+
+import com.alibaba.smartfox.eclipse.job.CodeAnalysis.processResources
+import com.alibaba.smartfox.eclipse.message.P3cBundle
+import com.google.common.collect.Sets
+import org.apache.log4j.Logger
+import org.eclipse.core.commands.AbstractHandler
+import org.eclipse.core.commands.ExecutionEvent
+import org.eclipse.core.commands.ExecutionException
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.resources.IResource
+import org.eclipse.core.resources.IResourceVisitor
+import org.eclipse.core.runtime.IAdaptable
+import org.eclipse.jface.viewers.IStructuredSelection
+import org.eclipse.ui.IFileEditorInput
+import org.eclipse.ui.IWorkingSet
+import org.eclipse.ui.commands.IElementUpdater
+import org.eclipse.ui.handlers.HandlerUtil
+import org.eclipse.ui.menus.UIElement
+import org.eclipse.ui.part.EditorPart
+import org.eclipse.ui.part.ViewPart
+
+/**
+ * @author caikang
+ * @date 2016/12/27
+ */
+open class CodeAnalysisHandler : AbstractHandler(), IElementUpdater {
+    override fun updateElement(element: UIElement, parameters: MutableMap<Any?, Any?>?) {
+        val text = P3cBundle.getMessage("com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler")
+        element.setText(text)
+        element.setTooltip(text)
+    }
+
+    @Throws(ExecutionException::class)
+    override fun execute(executionEvent: ExecutionEvent): Any? {
+        val selection = HandlerUtil.getCurrentSelectionChecked(executionEvent)
+        val part = HandlerUtil.getActivePart(executionEvent)
+        if (part is ViewPart) {
+            if (selection is IStructuredSelection) {
+                processForMutiFiles(selection)
+            }
+        } else if (part is EditorPart) {
+            val editorInput = HandlerUtil.getActiveEditorInput(executionEvent)
+            if (editorInput is IFileEditorInput) {
+                processResources(setOf(editorInput.file))
+            }
+        }
+        return null
+    }
+
+    private fun processForMutiFiles(selection: IStructuredSelection) {
+        val resources = getSelectionResources(selection)
+        processResources(resources)
+    }
+
+    private fun getSelectionResources(selection: IStructuredSelection): MutableSet<IResource> {
+        val resources = mutableSetOf<IResource>()
+        selection.toList().forEach {
+            when (it) {
+                is IWorkingSet -> it.elements.mapTo(resources) { it.getAdapter(IResource::class.java) as IResource }
+                is IAdaptable -> {
+                    val file = it.getAdapter(IResource::class.java) as? IResource ?: return@forEach
+                    resources.add(file)
+                }
+                else -> log.warn("The selected object is not adaptable : ${it.toString()}")
+            }
+        }
+        return resources
+    }
+
+
+    companion object {
+        private val log = Logger.getLogger(CodeAnalysisHandler::class.java)
+    }
+}
+
+class FileCollectVisitor : IResourceVisitor {
+    val fileSet = Sets.newLinkedHashSet<IFile>()!!
+
+    override fun visit(resource: IResource?): Boolean {
+        if (resource == null) {
+            return false
+        }
+        val file = resource.getAdapter(IFile::class.java) as? IFile ?: return true
+        if (file.exists() && (file.fileExtension == "java" || file.fileExtension == "vm")) {
+            fileSet.add(file)
+        }
+        return false
+    }
+}

+ 52 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/handler/SwitchLanguageHandler.kt

@@ -0,0 +1,52 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.handler
+
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import com.alibaba.smartfox.eclipse.message.P3cBundle
+import org.eclipse.core.commands.AbstractHandler
+import org.eclipse.core.commands.ExecutionEvent
+import org.eclipse.jface.dialogs.MessageDialog
+import org.eclipse.ui.PlatformUI
+import org.eclipse.ui.commands.IElementUpdater
+import org.eclipse.ui.menus.UIElement
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/21
+ */
+class SwitchLanguageHandler : AbstractHandler(), IElementUpdater {
+    val handlerKey = "com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler"
+    val textKey = "$handlerKey.text.cur_"
+
+    override fun execute(executionEvent: ExecutionEvent): Any? {
+        SmartfoxActivator.instance.toggleLocale()
+        if (!MessageDialog.openConfirm(null, "Tips",
+                P3cBundle.getMessage("$handlerKey.success.${SmartfoxActivator.instance.locale}"))) {
+            return null
+        }
+        PlatformUI.getWorkbench().restart()
+        return null
+    }
+
+    override fun updateElement(element: UIElement, parameters: MutableMap<Any?, Any?>?) {
+        val text = P3cBundle.getMessage("$textKey${SmartfoxActivator.instance.locale}")
+        element.setText(text)
+        element.setTooltip(text)
+    }
+}

+ 133 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/job/CodeAnalysis.kt

@@ -0,0 +1,133 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.job
+
+import com.alibaba.p3c.pmd.lang.java.util.GeneratedCodeUtils
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler
+import com.alibaba.smartfox.eclipse.handler.FileCollectVisitor
+import com.alibaba.smartfox.eclipse.ui.InspectionResultView
+import com.alibaba.smartfox.eclipse.ui.InspectionResults
+import com.alibaba.smartfox.eclipse.ui.MarkerViolation
+import com.alibaba.smartfox.eclipse.util.MarkerUtil
+import com.google.common.io.Files
+import net.sourceforge.pmd.PMDConfiguration
+import net.sourceforge.pmd.PMDException
+import net.sourceforge.pmd.Report
+import net.sourceforge.pmd.RuleContext
+import net.sourceforge.pmd.RuleViolation
+import net.sourceforge.pmd.SourceCodeProcessor
+import org.apache.log4j.Logger
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.resources.IResource
+import org.eclipse.core.runtime.IProgressMonitor
+import org.eclipse.core.runtime.IStatus
+import org.eclipse.core.runtime.Status
+import org.eclipse.core.runtime.SubMonitor
+import org.eclipse.core.runtime.jobs.Job
+import java.io.IOException
+import java.io.StringReader
+import java.nio.charset.Charset
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/14
+ */
+object CodeAnalysis {
+    private val log = Logger.getLogger(CodeAnalysisHandler::class.java)
+
+    fun processResources(resources: Set<IResource>) {
+        InspectionResultView.activeViews()
+        val job = object : Job("P3C Code Analysis") {
+            override fun run(monitor: IProgressMonitor): IStatus {
+                val fileVisitor = FileCollectVisitor()
+                monitor.setTaskName("Collect files")
+                resources.forEach {
+                    if (monitor.isCanceled) {
+                        return@run Status.CANCEL_STATUS
+                    }
+                    if (it.isAccessible) {
+                        it.accept(fileVisitor)
+                    }
+                }
+                if (monitor.isCanceled) {
+                    return Status.CANCEL_STATUS
+                }
+                val subMonitor = SubMonitor.convert(monitor, "Analysis files", fileVisitor.fileSet.size)
+                monitor.setTaskName("Analysis files")
+                fileVisitor.fileSet.forEach { iFile ->
+                    if (monitor.isCanceled) {
+                        return@run Status.CANCEL_STATUS
+                    }
+                    MarkerUtil.removeAllMarkers(iFile)
+                    monitor.subTask(iFile.fullPath.toPortableString())
+                    val markers = processFileToMakers(iFile, monitor)
+                    subMonitor.newChild(1)
+                    InspectionResults.updateFileViolations(iFile, markers)
+                }
+                return Status.OK_STATUS
+            }
+        }
+        job.apply {
+            isUser = true
+            isSystem = false
+            priority = Job.INTERACTIVE
+            rule = P3cMutex
+            schedule()
+        }
+    }
+
+    fun processFileToMakers(file: IFile, monitor: IProgressMonitor): List<MarkerViolation> {
+        file.refreshLocal(IResource.DEPTH_ZERO, monitor)
+        val ruleViolations = processFile(file)
+
+        MarkerUtil.removeAllMarkers(file)
+        return ruleViolations.map {
+            MarkerViolation(MarkerUtil.addMarker(file, it), it)
+        }
+    }
+
+    private fun processFile(file: IFile): List<RuleViolation> {
+        val configuration = PMDConfiguration()
+        configuration.setSourceEncoding(file.charset ?: Charsets.UTF_8.name())
+        configuration.inputPaths = file.fullPath.toPortableString()
+        val ctx = RuleContext()
+        ctx.setAttribute("eclipseFile", file)
+        val niceFileName = configuration.inputPaths
+        val report = Report.createReport(ctx, niceFileName)
+        SmartfoxActivator.instance.ruleSets.start(ctx)
+        val processor = SourceCodeProcessor(configuration)
+        try {
+            ctx.languageVersion = null
+            val content = Files.toString(file.rawLocation.toFile(), Charset.forName(file.charset))
+            if (!GeneratedCodeUtils.isGenerated(content)) {
+                processor.processSourceCode(StringReader(content), SmartfoxActivator.instance.ruleSets, ctx)
+            }
+        } catch (pmde: PMDException) {
+            log.debug("Error while processing file: " + niceFileName, pmde.cause)
+            report.addError(Report.ProcessingError(pmde, niceFileName))
+        } catch (ioe: IOException) {
+            log.error("Unable to read source file: " + niceFileName, ioe)
+        } catch (re: RuntimeException) {
+            log.error("RuntimeException while processing file: " + niceFileName, re)
+        } finally {
+            SmartfoxActivator.instance.ruleSets.end(ctx)
+        }
+        return report.toList()
+    }
+}

+ 34 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/job/P3cMutex.kt

@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.job
+
+import org.eclipse.core.runtime.jobs.ISchedulingRule
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/14
+ */
+object P3cMutex : ISchedulingRule {
+    override fun contains(rule: ISchedulingRule?): Boolean {
+        return isConflicting(rule)
+    }
+
+    override fun isConflicting(rule: ISchedulingRule?): Boolean {
+        return rule == this
+    }
+}

+ 37 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/message/P3cBundle.kt

@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.message
+
+
+import com.alibaba.p3c.pmd.I18nResources
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import java.util.Locale
+import java.util.ResourceBundle
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/20
+ */
+object P3cBundle {
+    private val resourceBundle = ResourceBundle.getBundle("messages.P3cBundle",
+            Locale(SmartfoxActivator.instance.locale), I18nResources.XmlControl())
+
+    fun getMessage(key: String): String {
+        return resourceBundle.getString(key)
+    }
+}

+ 35 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/RulePriority.kt

@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.pmd
+
+enum class RulePriority(val priority: Int, val title: String) {
+
+    Blocker(1, "Blocker"), Critical(2, "Critical"), Major(3, "Major");
+
+    override fun toString(): String {
+        return title
+    }
+
+    companion object {
+        fun valueOf(priority: Int): RulePriority {
+            try {
+                return RulePriority.values()[priority - 1]
+            } catch (e: ArrayIndexOutOfBoundsException) {
+                return Major
+            }
+        }
+    }
+}

+ 185 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AbstractEclipseRule.kt

@@ -0,0 +1,185 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.pmd.rule
+
+import com.alibaba.smartfox.eclipse.message.P3cBundle
+import net.sourceforge.pmd.Rule
+import net.sourceforge.pmd.RuleContext
+import net.sourceforge.pmd.RuleViolation
+import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit
+import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.runtime.NullProgressMonitor
+import org.eclipse.jdt.core.ICompilationUnit
+import org.eclipse.jdt.core.IProblemRequestor
+import org.eclipse.jdt.core.JavaCore
+import org.eclipse.jdt.core.JavaModelException
+import org.eclipse.jdt.core.WorkingCopyOwner
+import org.eclipse.jdt.core.compiler.IProblem
+import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.ASTVisitor
+import org.eclipse.jdt.core.dom.CompilationUnit
+import java.util.MissingResourceException
+
+/**
+ * @author caikang
+ * @date 2016/12/26
+ */
+abstract class AbstractEclipseRule : AbstractJavaRule() {
+
+    open fun getErrorMessage(): String {
+        return message
+    }
+
+    override fun visit(node: ASTCompilationUnit, data: Any): Any? {
+        val result = super.visit(node, data)
+        val ruleContext = data as RuleContext
+        val file = ruleContext.getAttribute("eclipseFile") as? IFile ?: return result
+        val compilationUnit = JavaCore.createCompilationUnitFrom(file) ?: return data
+        try {
+            val requestor = object : IProblemRequestor {
+                override fun acceptProblem(problem: IProblem) {}
+
+                override fun beginReporting() {}
+
+                override fun endReporting() {}
+
+                override fun isActive(): Boolean {
+                    return true
+                }
+            }
+            val workingCopy = compilationUnit.getWorkingCopy(null)
+            val ast = workingCopy.reconcile(JLS8, ICompilationUnit.FORCE_PROBLEM_DETECTION
+                    or ICompilationUnit.ENABLE_BINDINGS_RECOVERY or ICompilationUnit.ENABLE_STATEMENTS_RECOVERY,
+                    object : WorkingCopyOwner() {
+                        override fun getProblemRequestor(workingCopy: ICompilationUnit?): IProblemRequestor {
+                            return requestor
+                        }
+                    }, NullProgressMonitor()) ?: return data
+            ast.accept(getVisitor(ast, ruleContext))
+
+        } catch (e: JavaModelException) {
+            throw RuntimeException(e)
+        }
+
+        return data
+    }
+
+    override fun setDescription(description: String?) {
+        try {
+            super.setDescription(P3cBundle.getMessage(description ?: ""))
+        } catch (e: MissingResourceException) {
+            super.setMessage(description)
+        }
+
+    }
+
+    override fun setMessage(message: String) {
+        try {
+            super.setMessage(P3cBundle.getMessage(message))
+        } catch (e: MissingResourceException) {
+            super.setMessage(message)
+        }
+
+    }
+
+
+    protected abstract fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor
+
+    internal fun addRuleViolation(ruleContext: RuleContext, ast: CompilationUnit, nodeInfo: NodeInfo) {
+        val rule = this
+        val ruleViolation = object : RuleViolation {
+            override fun getRule(): Rule {
+                return rule
+            }
+
+            override fun getDescription(): String {
+                return getErrorMessage().trim { it <= ' ' }
+            }
+
+            override fun isSuppressed(): Boolean {
+                return false
+            }
+
+            override fun getFilename(): String {
+                return ruleContext.sourceCodeFilename
+            }
+
+            override fun getBeginLine(): Int {
+                return ast.getLineNumber(nodeInfo.startPosition)
+            }
+
+            override fun getBeginColumn(): Int {
+                return ast.getColumnNumber(nodeInfo.startPosition)
+            }
+
+            override fun getEndLine(): Int {
+                return ast.getLineNumber(nodeInfo.endPosition)
+            }
+
+            override fun getEndColumn(): Int {
+                return ast.getColumnNumber(nodeInfo.endPosition)
+            }
+
+            override fun getPackageName(): String? {
+                return nodeInfo.packageName
+            }
+
+            override fun getClassName(): String? {
+                return nodeInfo.className
+            }
+
+            override fun getMethodName(): String? {
+                return nodeInfo.methodName
+            }
+
+            override fun getVariableName(): String? {
+                return nodeInfo.variableName
+            }
+
+            override fun toString(): String {
+                return rule.toString()
+            }
+
+
+        }
+
+        ruleContext.report.addRuleViolation(ruleViolation)
+    }
+
+    protected fun violation(rc: RuleContext, node: ASTNode, ast: CompilationUnit) {
+        val nodeInfo = NodeInfo()
+        nodeInfo.className = ast.javaElement.elementName
+        nodeInfo.packageName = ast.`package`.name.fullyQualifiedName
+        nodeInfo.startPosition = node.startPosition
+        nodeInfo.endPosition = node.startPosition + node.length
+
+        addRuleViolation(rc, ast, nodeInfo)
+    }
+
+    inner class NodeInfo {
+        internal var packageName: String? = null
+        internal var className: String? = null
+        internal var methodName: String? = null
+        internal var variableName: String? = null
+        internal var startPosition: Int = 0
+        internal var endPosition: Int = 0
+    }
+
+    companion object {
+        val JLS8 = 8
+    }
+}

+ 110 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AvoidAccessStaticViaInstanceRule.kt

@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.pmd.rule
+
+import net.sourceforge.pmd.RuleContext
+import org.eclipse.jdt.core.dom.ASTVisitor
+import org.eclipse.jdt.core.dom.ClassInstanceCreation
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.core.dom.FieldAccess
+import org.eclipse.jdt.core.dom.IVariableBinding
+import org.eclipse.jdt.core.dom.MethodInvocation
+import org.eclipse.jdt.core.dom.Modifier
+import org.eclipse.jdt.core.dom.QualifiedName
+import org.eclipse.jdt.core.dom.SimpleName
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment
+
+/**
+ * @author caikang
+ * @date 2016/12/27
+ */
+class AvoidAccessStaticViaInstanceRule : AbstractEclipseRule() {
+    override fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor {
+        return object : ASTVisitor() {
+            override fun visit(node: QualifiedName?): Boolean {
+                val parent = node!!.parent
+                if (parent !is MethodInvocation && parent !is VariableDeclarationFragment) {
+                    return false
+                }
+                val name = node.name
+                val binding = name.resolveBinding()
+                if (binding !is IVariableBinding || binding.getModifiers() and Modifier.STATIC == 0) {
+                    return true
+                }
+                val qualifier = node.qualifier
+                val typeBinding = qualifier.resolveTypeBinding()
+                if (qualifier.isSimpleName) {
+                    when (parent) {
+                        is MethodInvocation -> {
+                            val methodBinding = parent.resolveMethodBinding()
+                            val methodTypeBinding = methodBinding.declaringClass
+                            if (methodBinding.modifiers and Modifier.STATIC != 0
+                                    && qualifier.fullyQualifiedName != methodTypeBinding.name
+                                    && methodTypeBinding == typeBinding && binding.name != typeBinding.name) {
+                                violation(ruleContext, parent, ast)
+                                return false
+                            }
+                        }
+                        else -> {
+                        }
+                    }
+                    if (typeBinding.name != qualifier.fullyQualifiedName) {
+                        violation(ruleContext, node, ast)
+                        return false
+                    }
+                }
+                if (qualifier.isQualifiedName) {
+                    val qualifiedName = qualifier as QualifiedName
+                    if (typeBinding.name != qualifiedName.name.identifier) {
+                        violation(ruleContext, node, ast)
+                        return false
+                    }
+                }
+                return true
+            }
+
+            override fun visit(node: FieldAccess): Boolean {
+                val variableBinding = node.resolveFieldBinding() ?: return false
+                if (variableBinding.modifiers and Modifier.STATIC == 0) {
+                    return true
+                }
+                if (node.expression is ClassInstanceCreation) {
+                    violation(ruleContext, node, ast)
+                    return true
+                }
+                return true
+            }
+
+            override fun visit(node: MethodInvocation?): Boolean {
+                val methodBinding = node?.resolveMethodBinding() ?: return false
+                if (methodBinding.modifiers and Modifier.STATIC == 0) {
+                    return true
+                }
+                if (node.expression is ClassInstanceCreation) {
+                    violation(ruleContext, node, ast)
+                    return true
+                }
+                val expression = node.expression
+                if (expression is SimpleName && expression.identifier != expression.resolveTypeBinding().name) {
+                    violation(ruleContext, node, ast)
+                    return true
+                }
+                return true
+            }
+        }
+    }
+
+}

+ 107 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AvoidUseDeprecationRule.kt

@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.pmd.rule
+
+import net.sourceforge.pmd.RuleContext
+import org.eclipse.jdt.core.dom.ASTVisitor
+import org.eclipse.jdt.core.dom.ClassInstanceCreation
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.core.dom.FieldAccess
+import org.eclipse.jdt.core.dom.IVariableBinding
+import org.eclipse.jdt.core.dom.ImportDeclaration
+import org.eclipse.jdt.core.dom.MethodInvocation
+import org.eclipse.jdt.core.dom.Modifier
+import org.eclipse.jdt.core.dom.QualifiedName
+import org.eclipse.jdt.core.dom.TypeDeclaration
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment
+
+/**
+ * @author caikang
+ * @date 2016/12/27
+ */
+class AvoidUseDeprecationRule : AbstractEclipseRule() {
+    override fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor {
+        return object : ASTVisitor() {
+            override fun visit(node: ImportDeclaration?): Boolean {
+                if (node!!.resolveBinding() != null && node.resolveBinding().isDeprecated) {
+                    violation(ruleContext, node, ast)
+                }
+                return true
+            }
+
+            override fun visit(node: QualifiedName?): Boolean {
+                if (node!!.parent !is MethodInvocation && node.parent !is VariableDeclarationFragment) {
+                    return false
+                }
+                val name = node.name
+                val binding = name.resolveBinding()
+                if (binding !is IVariableBinding || binding.getModifiers() and Modifier.STATIC == 0) {
+                    return true
+                }
+                if (binding.isDeprecated()) {
+                    violation(ruleContext, node, ast)
+                    return false
+                }
+                val qualifier = node.qualifier
+                val typeBinding = qualifier.resolveTypeBinding()
+                if (typeBinding.isDeprecated) {
+                    violation(ruleContext, node, ast)
+                    return false
+                }
+                return true
+            }
+
+            override fun visit(node: TypeDeclaration?): Boolean {
+                val superClass = node!!.superclassType
+                if (superClass != null && superClass.resolveBinding().isDeprecated) {
+                    violation(ruleContext, node, ast)
+                    return true
+                }
+                val interfaces = node.resolveBinding().interfaces
+                for (tb in interfaces) {
+                    if (tb.isDeprecated) {
+                        violation(ruleContext, node, ast)
+                        return true
+                    }
+                }
+                return true
+            }
+
+            override fun visit(node: FieldAccess?): Boolean {
+                val variableBinding = node!!.resolveFieldBinding() ?: return false
+                if (variableBinding.isDeprecated) {
+                    violation(ruleContext, node, ast)
+                }
+                return true
+            }
+
+            override fun visit(node: MethodInvocation): Boolean {
+                val methodBinding = node.resolveMethodBinding() ?: return false
+                if (methodBinding.isDeprecated) {
+                    violation(ruleContext, node, ast)
+                }
+                return true
+            }
+
+            override fun visit(node: ClassInstanceCreation?): Boolean {
+                if (node!!.resolveTypeBinding().isDeprecated) {
+                    violation(ruleContext, node, ast)
+                }
+                return true
+            }
+        }
+    }
+}

+ 132 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/MapOrSetKeyShouldOverrideHashCodeEqualsRule.kt

@@ -0,0 +1,132 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.pmd.rule
+
+import net.sourceforge.pmd.RuleContext
+import org.eclipse.jdt.core.dom.ASTVisitor
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.core.dom.ITypeBinding
+import org.eclipse.jdt.core.dom.MethodInvocation
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement
+
+/**
+ * @author zenghou.fw
+ * @date 2016/12/27
+ */
+class MapOrSetKeyShouldOverrideHashCodeEqualsRule : AbstractEclipseRule() {
+
+    val methodEquals = "equals"
+    val methodHashCode = "hashCode"
+    val methodAdd = "add"
+    val methodPut = "put"
+
+    private val skipJdkPackageJava = "java."
+    private val skipJdkPackageJavax = "javax."
+
+    override fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor {
+        return object : ASTVisitor() {
+
+            override fun visit(node: VariableDeclarationStatement): Boolean {
+                if (!node.type.isParameterizedType) {
+                    return true
+                }
+                val typeBinding = node.type.resolveBinding()
+                if (isSet(typeBinding) || isMap(typeBinding)) {
+                    val argumentTypes = typeBinding.typeArguments
+                    if (argumentTypes != null && argumentTypes.isNotEmpty()) {
+                        if (!isOverrideEqualsAndHashCode(argumentTypes[0])) {
+                            violation(ruleContext, node, ast)
+                            return false
+                        }
+                    }
+                }
+                return true
+            }
+
+            override fun visit(node: MethodInvocation): Boolean {
+                val methodBinding = node.resolveMethodBinding() ?: return false
+                val callerType = methodBinding.declaringClass
+
+                if (methodAdd == methodBinding.name) {
+                    if (!isSet(callerType)) {
+                        return true
+                    }
+                    val parameterTypes = methodBinding.parameterTypes
+                    if (parameterTypes != null && parameterTypes.isNotEmpty()) {
+                        if (!isOverrideEqualsAndHashCode(parameterTypes[0])) {
+                            violation(ruleContext, node, ast)
+                            return false
+                        }
+                    }
+                    return true
+                }
+                if (methodPut == methodBinding.name) {
+                    if (!isMap(callerType)) {
+                        return true
+                    }
+                    val parameterTypes = methodBinding.parameterTypes
+                    if (parameterTypes != null && parameterTypes.isNotEmpty()) {
+                        if (!isOverrideEqualsAndHashCode(parameterTypes[0])) {
+                            violation(ruleContext, node, ast)
+                            return false
+                        }
+                    }
+                }
+                return true
+            }
+
+            private fun isOverrideEqualsAndHashCode(genericType: ITypeBinding): Boolean {
+                val skip = genericType.isEnum || genericType.isInterface || genericType.isArray
+                        || genericType.isTypeVariable || genericType.isWildcardType
+                        || genericType.qualifiedName?.startsWith(skipJdkPackageJava) ?: false
+                        || genericType.qualifiedName?.startsWith(skipJdkPackageJavax) ?: false
+                // skip
+                if (skip) {
+                    return true
+                }
+
+                val methodBindings = genericType.declaredMethods ?: return false
+
+                val overrideCount = methodBindings.asSequence().filter {
+                    //find equals(Object o) and hashCode() with @Override
+                    methodEquals == it.name || methodHashCode == it.name
+                }.filter {
+                    when (it.name) {
+                        methodEquals -> {
+                            val parameterTypes = it.parameterTypes
+                            parameterTypes != null && parameterTypes.isNotEmpty()
+                                    && Object::class.java.name == parameterTypes[0].qualifiedName
+                        }
+                        methodHashCode -> {
+                            val parameterTypes = it.parameterTypes
+                            parameterTypes == null || parameterTypes.isEmpty()
+                        }
+                        else -> false
+                    }
+                }.count()
+                return overrideCount == 2
+            }
+
+            private fun isSet(typeBinding: ITypeBinding): Boolean {
+                return java.util.Set::class.java.name == typeBinding.binaryName
+            }
+
+            private fun isMap(typeBinding: ITypeBinding): Boolean {
+                return java.util.Map::class.java.name == typeBinding.binaryName
+            }
+        }
+    }
+}

+ 84 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/MissingOverrideAnnotationRule.kt

@@ -0,0 +1,84 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.pmd.rule
+
+import com.alibaba.smartfox.eclipse.message.P3cBundle
+import net.sourceforge.pmd.RuleContext
+import org.eclipse.jdt.core.dom.ASTVisitor
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding
+import java.util.Arrays
+import javax.annotation.Generated
+
+/**
+ * @author caikang
+ * @date 2016/12/24
+ */
+class MissingOverrideAnnotationRule : AbstractEclipseRule() {
+    override fun getErrorMessage(): String {
+        return P3cBundle.getMessage("rule.standalone.MissingOverrideAnnotationRule.error")
+    }
+
+    override fun getVisitor(ast: CompilationUnit, ruleContext: RuleContext): ASTVisitor {
+        return MissingOverrideVisitor(ast, ruleContext)
+    }
+
+    private inner class MissingOverrideVisitor(private val ast: CompilationUnit,
+            private val ruleContext: RuleContext) : ASTVisitor() {
+
+        override fun visit(node: MethodDeclaration?): Boolean {
+            val methodBinding = node!!.resolveBinding()
+            val declaringClass = methodBinding.declaringClass ?: return super.visit(node)
+            if (declaringClass.isInterface) {
+                return super.visit(node)
+            }
+            val abs = methodBinding.annotations
+            if (abs.any {
+                Override::class.java.canonicalName == it.annotationType.binaryName
+            }) {
+                return super.visit(node)
+            }
+            try {
+                val field = methodBinding.javaClass.getDeclaredField("binding")
+                field.isAccessible = true
+                val internalBinding = field.get(methodBinding) as MethodBinding
+                if (internalBinding.isStatic || !(internalBinding.isImplementing || internalBinding.isOverriding)
+                        || isGenerated(internalBinding)) {
+                    return super.visit(node)
+                }
+                violation(ruleContext, node, ast)
+            } catch (e: Exception) {
+                e.printStackTrace()
+            }
+
+            return super.visit(node)
+        }
+
+        /**
+         * skip @Override check for generated code by lombok
+         * @param internalBinding
+         * @return
+         */
+        private fun isGenerated(internalBinding: MethodBinding): Boolean {
+            val annotationBindings = internalBinding.annotations ?: return false
+            return annotationBindings.any {
+                it.annotationType != null && Arrays.equals(Generated::class.java.name.toCharArray(),
+                        it.annotationType.readableName())
+            }
+        }
+    }
+}

+ 36 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/AllRulesPreferencePage.kt

@@ -0,0 +1,36 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import org.eclipse.jface.preference.PreferencePage
+import org.eclipse.swt.widgets.Composite
+import org.eclipse.swt.widgets.Control
+import org.eclipse.ui.IWorkbench
+import org.eclipse.ui.IWorkbenchPreferencePage
+
+/**
+ *
+ * @author caikang
+ * @date 2017/09/01
+ */
+class AllRulesPreferencePage : PreferencePage(), IWorkbenchPreferencePage {
+    override fun init(parent: IWorkbench?) {
+    }
+
+    override fun createContents(parent: Composite): Control {
+        return AllRulesView(parent).content
+    }
+}

+ 49 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/AllRulesView.kt

@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import org.eclipse.swt.SWT
+import org.eclipse.swt.layout.FillLayout
+import org.eclipse.swt.widgets.Composite
+import org.eclipse.swt.widgets.List
+
+
+/**
+ *
+ * @author caikang
+ * @date 2017/09/01
+ */
+class AllRulesView(parent: Composite) {
+    val content = Composite(parent, SWT.NONE)
+
+    private val ruleList = SmartfoxActivator.instance.ruleSets.allRules.toList()
+
+    init {
+        content.layout = FillLayout()
+        val list = List(content, SWT.BORDER or SWT.SINGLE or SWT.V_SCROLL or SWT.PUSH or SWT.H_SCROLL)
+        ruleList.forEach {
+            list.add(it.message)
+        }
+        val ruleDetail = RuleDetailComposite(content, SWT.PUSH)
+        list.addListener(SWT.Selection) {
+            val index = list.selectionIndex
+            val rule = ruleList.getOrNull(index) ?: return@addListener
+            ruleDetail.refresh(rule)
+        }
+        list.select(0)
+    }
+}

+ 68 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultTreeContentProvider.kt

@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import org.eclipse.jface.viewers.ITreeContentProvider
+import org.eclipse.jface.viewers.Viewer
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/08
+ */
+object InspectionResultTreeContentProvider : ITreeContentProvider {
+    private lateinit var input: InspectionResults
+
+    override fun getParent(element: Any?): Any {
+        return input
+    }
+
+    override fun hasChildren(element: Any?): Boolean {
+        return element is InspectionResults || element is LevelViolations || element is RuleViolations
+                || element is FileMarkers
+    }
+
+    override fun getChildren(parentElement: Any?): Array<Any> {
+        if (parentElement is InspectionResults) {
+            return parentElement.errors.toTypedArray()
+        }
+        if (parentElement is LevelViolations) {
+            return parentElement.rules.toTypedArray()
+        }
+        if (parentElement is RuleViolations) {
+            return parentElement.files.toTypedArray()
+        }
+        if (parentElement is FileMarkers) {
+            return parentElement.markers.toTypedArray()
+        }
+        return emptyArray()
+    }
+
+    override fun getElements(inputElement: Any?): Array<Any> {
+        return input.errors.toTypedArray()
+    }
+
+    override fun inputChanged(viewer: Viewer?, oldInput: Any?, newInput: Any?) {
+        if (newInput == null) {
+            return
+        }
+        this.input = newInput as InspectionResults
+    }
+
+    override fun dispose() {
+    }
+}

+ 65 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultTreeLabelProvider.kt

@@ -0,0 +1,65 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import com.alibaba.smartfox.eclipse.pmd.RulePriority
+import org.eclipse.jface.viewers.LabelProvider
+import org.eclipse.swt.graphics.Image
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/08
+ */
+object InspectionResultTreeLabelProvider : LabelProvider() {
+    override fun getImage(element: Any?): Image? {
+        if (element is LevelViolations) {
+            val imageName = when (element.level) {
+                RulePriority.Blocker.title, RulePriority.Critical.title -> "${element.level}.gif".toLowerCase()
+                else -> "${element.level}.png".toLowerCase()
+            }
+            return SmartfoxActivator.instance.getImage("icons/view/$imageName")
+        }
+        if (element is FileMarkers) {
+            if (element.file.fullPath.toPortableString().endsWith("java")) {
+                return SmartfoxActivator.instance.getImage("icons/view/class_obj.png")
+            }
+            return SmartfoxActivator.instance.getImage("icons/view/file_obj.png")
+        }
+        return null
+    }
+
+    override fun getText(element: Any?): String {
+        if (element is LevelViolations) {
+            return "${element.level} (${element.count} Violations)"
+        }
+        if (element is RuleViolations) {
+            val rule = SmartfoxActivator.instance.getRule(element.rule)
+            return "${rule.message} (${element.count} Violations)"
+        }
+        if (element is FileMarkers) {
+            return element.file.fullPath.toPortableString().substringAfterLast("/") +
+                    " (${element.markers.size} Violations)"
+        }
+        if (element is MarkerViolation) {
+            val desc = element.violation.description
+            return "$desc (at line ${element.violation.beginLine})"
+        }
+        return element.toString()
+    }
+}

+ 249 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultView.kt

@@ -0,0 +1,249 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import com.alibaba.smartfox.eclipse.job.P3cMutex
+import com.alibaba.smartfox.eclipse.util.MarkerUtil
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.resources.IMarker
+import org.eclipse.core.runtime.IProgressMonitor
+import org.eclipse.core.runtime.IStatus
+import org.eclipse.core.runtime.Status
+import org.eclipse.core.runtime.jobs.Job
+import org.eclipse.jface.action.Action
+import org.eclipse.jface.action.Separator
+import org.eclipse.jface.util.OpenStrategy
+import org.eclipse.jface.viewers.ISelection
+import org.eclipse.jface.viewers.IStructuredSelection
+import org.eclipse.jface.viewers.ITreeSelection
+import org.eclipse.jface.viewers.TreeViewer
+import org.eclipse.swt.SWT
+import org.eclipse.swt.layout.FillLayout
+import org.eclipse.swt.widgets.Composite
+import org.eclipse.swt.widgets.Display
+import org.eclipse.ui.IWorkbenchPage
+import org.eclipse.ui.OpenAndLinkWithEditorHelper
+import org.eclipse.ui.PartInitException
+import org.eclipse.ui.PlatformUI
+import org.eclipse.ui.ide.IDE
+import org.eclipse.ui.ide.ResourceUtil
+import org.eclipse.ui.internal.views.markers.MarkerSupportInternalUtilities
+import org.eclipse.ui.part.ViewPart
+import org.eclipse.ui.texteditor.ITextEditor
+import java.util.HashSet
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/08
+ */
+class InspectionResultView : ViewPart() {
+    lateinit var treeViewer: TreeViewer
+
+    private val quickFixAction = QuickFixAction(this)
+
+    override fun setFocus() {
+        treeViewer.control.setFocus()
+    }
+
+    override fun createPartControl(parent: Composite) {
+        parent.layout = FillLayout()
+        treeViewer = TreeViewer(parent, SWT.MULTI or SWT.H_SCROLL or SWT.V_SCROLL)
+        treeViewer.setUseHashlookup(true)
+        treeViewer.contentProvider = InspectionResultTreeContentProvider
+        treeViewer.labelProvider = InspectionResultTreeLabelProvider
+        treeViewer.input = InspectionResults
+
+        InspectionResults.view = this
+
+        addDoubleClickListener()
+
+        addSelectionChangedListener()
+
+        initToolBar()
+
+        addLinkWithEditorSupport()
+        site.selectionProvider = treeViewer
+    }
+
+    fun clear() {
+        InspectionResults.clear()
+        refreshView(InspectionResults)
+    }
+
+    fun refreshView(input: InspectionResults) {
+        Display.getDefault().asyncExec {
+            treeViewer.refresh(input, true)
+            contentDescription = input.contentDescription
+        }
+    }
+
+    private fun addSelectionChangedListener() {
+        treeViewer.addSelectionChangedListener inner@ {
+            val selection = it.selection as? IStructuredSelection ?: return@inner
+            val item = selection.firstElement ?: return@inner
+            val ruleDetailView = RuleDetailView.showAndGetView()
+            when (item) {
+                is MarkerViolation -> {
+                    ruleDetailView.refresh(item.violation.rule)
+                    quickFixAction.updateFileMarkers(listOf(FileMarkers(item.marker.resource as IFile, listOf(item))))
+                }
+                is FileMarkers -> {
+                    ruleDetailView.refresh(item.markers.first().violation.rule)
+                    quickFixAction.updateFileMarkers(listOf(item))
+                }
+                is RuleViolations -> {
+                    ruleDetailView.refresh(SmartfoxActivator.instance.getRule(item.rule))
+                    quickFixAction.updateFileMarkers(item.files)
+                }
+                else -> {
+                    quickFixAction.updateFileMarkers(emptyList())
+                }
+            }
+        }
+    }
+
+    private fun initToolBar() {
+        val bars = viewSite.actionBars
+        val tm = bars.toolBarManager
+
+        val clearAction = object : Action("Clear Markers") {
+            override fun run() {
+                val job = object : Job("Clear Markers") {
+                    override fun run(monitor: IProgressMonitor): IStatus {
+                        if (monitor.isCanceled) {
+                            Status.CANCEL_STATUS
+                        }
+                        clear()
+                        return Status.OK_STATUS
+                    }
+                }
+                job.rule = P3cMutex
+                job.schedule()
+            }
+        }
+
+        clearAction.imageDescriptor = SmartfoxActivator.getImageDescriptor("icons/actions/clear.png")
+
+        tm.add(Separator("Markers"))
+        tm.add(clearAction)
+
+        tm.add(Separator("FilterGroup"))
+        tm.add(quickFixAction)
+    }
+
+    private fun addLinkWithEditorSupport() {
+        object : OpenAndLinkWithEditorHelper(treeViewer) {
+            override fun activate(selection: ISelection) {
+                val currentMode = OpenStrategy.getOpenMethod()
+                try {
+                    OpenStrategy.setOpenMethod(OpenStrategy.DOUBLE_CLICK)
+                    openSelectedMarkers()
+                } finally {
+                    OpenStrategy.setOpenMethod(currentMode)
+                }
+            }
+
+            override fun linkToEditor(selection: ISelection?) {
+            }
+
+            override fun open(selection: ISelection, activate: Boolean) {
+                val structured = selection as ITreeSelection
+                val element = structured.firstElement as? MarkerViolation ?: return
+                val page = site.page
+                if (element.marker.exists()) {
+                    openMarkerInEditor(element.marker, page)
+                    return
+                }
+                val file = element.marker.resource as IFile
+                val editor = IDE.openEditor(page, file) as ITextEditor
+                editor.selectAndReveal(MarkerUtil.getAbsoluteRange(file, element.violation).start, 0)
+            }
+        }
+    }
+
+    internal fun openSelectedMarkers() {
+        val markers = getOpenableMarkers()
+        for (marker in markers) {
+            val page = site.page
+            openMarkerInEditor(marker, page)
+        }
+    }
+
+    private fun getOpenableMarkers(): Array<IMarker> {
+        val structured = treeViewer.selection as ITreeSelection
+        val elements = structured.iterator()
+        val result = HashSet<IMarker>()
+
+        while (elements.hasNext()) {
+            val marker = elements.next() as? IMarker ?: return emptyArray()
+            result.add(marker)
+        }
+        return result.toTypedArray()
+    }
+
+
+    fun openMarkerInEditor(marker: IMarker?, page: IWorkbenchPage) {
+        val editor = page.activeEditor
+        if (editor != null) {
+            val input = editor.editorInput
+            val file = ResourceUtil.getFile(input)
+            if (file != null) {
+                if (marker!!.resource == file && OpenStrategy.activateOnOpen()) {
+                    page.activate(editor)
+                }
+            }
+        }
+
+        if (marker != null && marker.resource is IFile) {
+            try {
+                IDE.openEditor(page, marker, OpenStrategy.activateOnOpen())
+            } catch (e: PartInitException) {
+                MarkerSupportInternalUtilities.showViewError(e)
+            }
+
+        }
+    }
+
+    private fun addDoubleClickListener() {
+        treeViewer.addDoubleClickListener({ event ->
+            val selection = event.selection
+            if (selection !is ITreeSelection || selection.size() != 1) {
+                return@addDoubleClickListener
+            }
+            val obj = selection.firstElement
+            if (treeViewer.isExpandable(obj)) {
+                treeViewer.setExpandedState(obj, !treeViewer.getExpandedState(obj))
+            }
+        })
+    }
+
+    companion object {
+        val viewId = "com.alibaba.smartfox.eclipse.ui.InspectionResultView"
+
+        fun activeViews() {
+            PlatformUI.getWorkbench().activeWorkbenchWindow.activePage.showView(viewId)
+            RuleDetailView.showAndGetView()
+        }
+
+        fun getView(): InspectionResultView {
+            return PlatformUI.getWorkbench().activeWorkbenchWindow.activePage.findView(viewId) as InspectionResultView
+        }
+    }
+}
+

+ 103 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResults.kt

@@ -0,0 +1,103 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import com.alibaba.smartfox.eclipse.pmd.RulePriority
+import com.alibaba.smartfox.eclipse.util.MarkerUtil
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.resources.IMarker
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/13
+ */
+object InspectionResults {
+    private val fileViolations = linkedMapOf<IFile, List<MarkerViolation>>()
+
+    var contentDescription = ""
+
+    val errors: List<LevelViolations>
+        get() {
+            val result = toLevelViolationList(fileViolations.values.flatten())
+            contentDescription = getContentDescription(result)
+            return result
+        }
+
+    lateinit var view: InspectionResultView
+
+
+    fun clear() {
+        fileViolations.forEach {
+            MarkerUtil.removeAllMarkers(it.key)
+        }
+        fileViolations.clear()
+        // update contentDescription
+        errors
+    }
+
+    private fun toLevelViolationList(markers: Collection<MarkerViolation>): List<LevelViolations> {
+        return markers.groupBy {
+            it.violation.rule.priority.priority
+        }.mapValues {
+            it.value.groupBy {
+                it.violation.rule.name
+            }.mapValues {
+                it.value.groupBy {
+                    it.marker.resource as IFile
+                }.map {
+                    FileMarkers(it.key, it.value)
+                }
+            }.map {
+                RuleViolations(it.key, it.value)
+            }
+        }.toSortedMap().map {
+            val level = RulePriority.valueOf(it.key).title
+            LevelViolations(level, it.value)
+        }
+    }
+
+    fun updateFileViolations(file: IFile, markers: List<MarkerViolation>) {
+        if (markers.isEmpty()) {
+            fileViolations.remove(file)
+        } else {
+            fileViolations[file] = markers
+        }
+        view.refreshView(this)
+    }
+
+    fun removeMarker(marker: IMarker) {
+        val file = marker.resource as IFile
+        val list = fileViolations[file] ?: return
+        val result = list.filter {
+            it.marker != marker
+        }
+        fileViolations[file] = result
+        marker.delete()
+        view.refreshView(this)
+    }
+
+    fun getContentDescription(errors: List<LevelViolations>): String {
+        val map = errors.associateBy {
+            it.level
+        }
+
+        return "${map[RulePriority.Blocker.title]?.count ?: 0} Blockers," +
+                "${map[RulePriority.Critical.title]?.count ?: 0} Criticals," +
+                "${map[RulePriority.Major.title]?.count ?: 0} Majors"
+    }
+}

+ 114 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/QuickFixAction.kt

@@ -0,0 +1,114 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import com.alibaba.p3c.pmd.lang.java.rule.flowcontrol.NeedBraceRule
+import com.alibaba.smartfox.eclipse.RunWithoutViewRefresh
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import com.alibaba.smartfox.eclipse.job.CodeAnalysis
+import com.alibaba.smartfox.eclipse.job.P3cMutex
+import com.alibaba.smartfox.eclipse.pmd.rule.MissingOverrideAnnotationRule
+import com.alibaba.smartfox.eclipse.util.CleanUps
+import com.alibaba.smartfox.eclipse.util.getResolution
+import org.eclipse.core.runtime.IProgressMonitor
+import org.eclipse.core.runtime.IStatus
+import org.eclipse.core.runtime.Status
+import org.eclipse.core.runtime.SubMonitor
+import org.eclipse.core.runtime.jobs.Job
+import org.eclipse.jface.action.Action
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/14
+ */
+class QuickFixAction(val view: InspectionResultView) : Action("Quick Fix") {
+    init {
+        imageDescriptor = SmartfoxActivator.getImageDescriptor("icons/actions/quickfixBulb.png")
+        isEnabled = false
+    }
+
+    var markers = listOf<FileMarkers>()
+
+    fun updateFileMarkers(markers: List<FileMarkers>) {
+        this.markers = markers
+        isEnabled = enabled()
+    }
+
+    override fun run() {
+        if (markers.isEmpty()) {
+            return
+        }
+        runJob()
+    }
+
+    private fun runJob() {
+        val job = object : Job("Perform P3C Quick Fix") {
+            override fun run(monitor: IProgressMonitor): IStatus {
+                val subMonitor = SubMonitor.convert(monitor, markers.size)
+                monitor.setTaskName("Process File")
+                markers.forEach {
+                    if (monitor.isCanceled) {
+                        return@run Status.CANCEL_STATUS
+                    }
+                    monitor.subTask(it.file.name)
+                    val childMonitor = subMonitor.newChild(1)
+                    if (useCleanUpRefactoring()) {
+                        CleanUps.fix(it.file, childMonitor)
+                    } else {
+                        it.markers.filter { it.marker.exists() }.forEach {
+                            (it.marker.getResolution() as RunWithoutViewRefresh).run(it.marker, true)
+                        }
+                    }
+                    val markers = CodeAnalysis.processFileToMakers(it.file, monitor)
+                    InspectionResults.updateFileViolations(it.file, markers)
+                }
+
+                return Status.OK_STATUS
+            }
+        }
+        val outJob = object:Job("P3C Quick Fix Wait analysis finish"){
+            override fun run(monitor: IProgressMonitor?): IStatus {
+                job.schedule()
+                return Status.OK_STATUS
+            }
+        }
+        outJob.rule = P3cMutex
+        outJob.schedule()
+
+    }
+
+    fun enabled(): Boolean {
+        if (useCleanUpRefactoring()) {
+            return true
+        }
+        if (markers.isEmpty()) {
+            return false
+        }
+        val marker = markers.first().markers.first().marker
+        return marker.exists() && marker.getResolution() != null
+    }
+
+    private fun useCleanUpRefactoring(): Boolean {
+        if (markers.isEmpty()) {
+            return false
+        }
+        val ruleName = markers.first().markers.first().violation.rule.name
+        return ruleName == MissingOverrideAnnotationRule::class.java.simpleName
+                || ruleName == NeedBraceRule::class.java.simpleName
+    }
+}

+ 83 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/RuleDetailComposite.kt

@@ -0,0 +1,83 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import com.alibaba.smartfox.eclipse.pmd.RulePriority
+import com.alibaba.smartfox.eclipse.ui.pmd.ContentBuilder
+import com.alibaba.smartfox.eclipse.ui.pmd.StringArranger
+import net.sourceforge.pmd.Rule
+import org.eclipse.swt.SWT
+import org.eclipse.swt.custom.StyledText
+import org.eclipse.swt.layout.FillLayout
+import org.eclipse.swt.widgets.Composite
+
+/**
+ *
+ * @author caikang
+ * @date 2017/09/01
+ */
+class RuleDetailComposite(parent: Composite, style: Int = SWT.NONE) {
+    private val viewField: StyledText
+    private val contentBuilder = ContentBuilder()
+    private val arranger = StringArranger("   ")
+    private val panel = Composite(parent, style)
+
+    init {
+        panel.layout = FillLayout()
+
+        viewField = StyledText(panel, SWT.BORDER or SWT.H_SCROLL or SWT.V_SCROLL)
+        viewField.wordWrap = true
+        viewField.tabs = 20
+        viewField.text = "Select a result item to show rule detail."
+        viewField.editable = false
+    }
+
+    fun refresh(rule: Rule) {
+        contentBuilder.clear()
+        viewField.text = ""
+        contentBuilder.addHeading("Name")
+        contentBuilder.addText(rule.name)
+        contentBuilder.addHeading("Severity")
+        contentBuilder.addText(RulePriority.valueOf(rule.priority.priority).title)
+        contentBuilder.addHeading("Message")
+        contentBuilder.addText(rule.message)
+        if (!rule.description.isNullOrBlank()) {
+            contentBuilder.addHeading("Description")
+            contentBuilder.addRawText(arranger.format(rule.description).toString())
+        }
+
+        val examples = rule.examples
+        if (examples.isEmpty()) {
+            contentBuilder.showOn(viewField)
+            return
+        }
+
+        contentBuilder.setLanguage(rule.language)
+
+        contentBuilder.addHeading("Examples")
+        contentBuilder.addText("")
+        for (example in rule.examples) {
+            contentBuilder.addCode(example.trim { it <= ' ' })
+            contentBuilder.addText("")
+        }
+        contentBuilder.showOn(viewField)
+
+        if (contentBuilder.hasLinks()) {
+            contentBuilder.addLinkHandler(viewField)
+        }
+        viewField.update()
+    }
+}

+ 92 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/RuleDetailView.kt

@@ -0,0 +1,92 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import net.sourceforge.pmd.Rule
+import org.eclipse.jface.action.Action
+import org.eclipse.jface.action.Separator
+import org.eclipse.swt.SWT
+import org.eclipse.swt.custom.ScrolledComposite
+import org.eclipse.swt.layout.FillLayout
+import org.eclipse.swt.widgets.Composite
+import org.eclipse.swt.widgets.Display
+import org.eclipse.swt.widgets.Shell
+import org.eclipse.ui.IWorkbenchPage
+import org.eclipse.ui.PlatformUI
+import org.eclipse.ui.part.ViewPart
+
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/12
+ */
+open class RuleDetailView : ViewPart() {
+
+    private lateinit var ruleDetailComposite: RuleDetailComposite
+
+    override fun setFocus() {
+    }
+
+    override fun createPartControl(parent: Composite) {
+        ruleDetailComposite = RuleDetailComposite(parent)
+        initToolBar()
+    }
+
+    fun refresh(rule: Rule) {
+        ruleDetailComposite.refresh(rule)
+    }
+
+
+    private fun initToolBar() {
+        val bars = viewSite.actionBars
+        val tm = bars.toolBarManager
+
+        val rulesAction = object : Action("Show Rules") {
+            override fun run() {
+                val shell = Shell(Display.getDefault())
+                shell.text = "All Rules"
+                shell.layout = FillLayout()
+
+                val sc = ScrolledComposite(shell, SWT.V_SCROLL or SWT.H_SCROLL)
+
+                val rulesView = AllRulesView(sc)
+
+                sc.expandHorizontal = true
+                sc.expandVertical = true
+
+                sc.content = rulesView.content
+
+                shell.open()
+            }
+        }
+
+        rulesAction.imageDescriptor = SmartfoxActivator.getImageDescriptor("icons/actions/rules.png")
+
+        tm.add(Separator("Markers"))
+        tm.add(rulesAction)
+    }
+
+    companion object {
+        fun showAndGetView(): RuleDetailView {
+            return PlatformUI.getWorkbench().activeWorkbenchWindow.activePage.showView(
+                    "com.alibaba.smartfox.eclipse.ui.RuleDetailView", null,
+                    IWorkbenchPage.VIEW_VISIBLE) as RuleDetailView
+        }
+    }
+}

+ 86 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/Violations.kt

@@ -0,0 +1,86 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.smartfox.eclipse.ui
+
+import com.alibaba.smartfox.eclipse.util.MarkerUtil
+import net.sourceforge.pmd.RuleViolation
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.resources.IMarker
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/13
+ */
+data class LevelViolations(var level: String, var rules: List<RuleViolations>,
+        var count: Int = rules.sumBy { it.count }) {
+    fun removeMarkers() {
+        rules.forEach {
+            it.removeMarkers()
+        }
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (other !is LevelViolations) {
+            return false
+        }
+        return level == other.level
+    }
+
+    override fun hashCode(): Int {
+        return level.hashCode()
+    }
+}
+
+data class RuleViolations(var rule: String, var files: List<FileMarkers>,
+        var count: Int = files.sumBy { it.markers.size }) {
+    fun removeMarkers() {
+        files.forEach {
+            it.removeMarkers()
+        }
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (other !is RuleViolations) {
+            return false
+        }
+        return rule == other.rule
+    }
+
+    override fun hashCode(): Int {
+        return rule.hashCode()
+    }
+}
+
+data class FileMarkers(var file: IFile, var markers: List<MarkerViolation>) {
+    fun removeMarkers() {
+        MarkerUtil.removeAllMarkers(file)
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (other !is FileMarkers) {
+            return false
+        }
+        return file == other.file
+    }
+
+    override fun hashCode(): Int {
+        return file.hashCode()
+    }
+}
+
+data class MarkerViolation(val marker: IMarker, val violation: RuleViolation)

+ 20 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/BasicLineStyleListener.kt

@@ -0,0 +1,20 @@
+package com.alibaba.smartfox.eclipse.ui.pmd
+
+import org.eclipse.swt.custom.LineStyleEvent
+import org.eclipse.swt.custom.LineStyleListener
+
+/**
+ * This class performs the syntax highlighting and styling for Pmpe
+ *  * PmpeLineStyleListener constructor
+
+ * @param theSyntaxData the syntax data to use
+ */
+class BasicLineStyleListener(theSyntaxData: SyntaxData) : StyleExtractor(theSyntaxData), LineStyleListener {
+    /**
+     * Called by StyledText to get styles for a line
+     */
+    override fun lineGetStyle(event: LineStyleEvent) {
+        val styles = lineStylesFor(event.lineText, event.lineOffset, event.lineText.length)
+        event.styles = styles.toTypedArray()
+    }
+}

+ 158 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/ContentBuilder.kt

@@ -0,0 +1,158 @@
+package com.alibaba.smartfox.eclipse.ui.pmd
+
+import net.sourceforge.pmd.lang.Language
+import org.eclipse.swt.SWT
+import org.eclipse.swt.custom.StyleRange
+import org.eclipse.swt.custom.StyledText
+import org.eclipse.swt.graphics.Point
+import org.eclipse.swt.widgets.Display
+import org.eclipse.ui.PlatformUI
+import java.net.URL
+import java.util.ArrayList
+import java.util.Arrays
+import java.util.HashMap
+
+/**
+ *
+ * @author caikang
+ * @date 2017/07/20
+ */
+class ContentBuilder {
+    private val CR = '\n'
+    private val buffer = StringBuilder()
+    private val headingSpans = ArrayList<IntArray>()
+    private val codeSpans = ArrayList<IntArray>()
+    private val linksBySpan = HashMap<IntArray, String>()
+
+    private val indentDepth: Int = 3
+
+    private val codeStyleExtractor = StyleExtractor(SyntaxManager.getSyntaxData("java"))
+
+    private val background = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)
+
+    private val headingColor = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)
+
+    private val codeStyle = FontBuilder("Courier", 11, SWT.NORMAL).style(Display.getCurrent())
+
+    fun clear() {
+        buffer.setLength(0)
+        headingSpans.clear()
+        codeSpans.clear()
+        linksBySpan.clear()
+    }
+
+    fun addHeading(heading: String) {
+        var length = buffer.length
+        if (length > 0) {
+            buffer.append(CR)
+            length += 1
+        }
+
+        headingSpans.add(intArrayOf(length, length + heading.length))
+        buffer.append(heading).append(CR)
+    }
+
+    fun addText(text: String) {
+        for (i in 0 until indentDepth) {
+            buffer.append(' ')
+        }
+        buffer.append(text).append(CR)
+    }
+
+    fun addRawText(text: String) {
+        buffer.append(text)
+    }
+
+    fun addCode(code: String) {
+        val length = buffer.length
+        codeSpans.add(intArrayOf(length, length + code.length))
+        buffer.append(code)
+    }
+
+    fun setLanguage(language: Language) {
+        val syntax = SyntaxManager.getSyntaxData(language.terseName)
+        codeStyleExtractor.syntax(syntax)
+    }
+
+    fun hasLinks(): Boolean {
+        return linksBySpan.isNotEmpty()
+    }
+
+    fun addLinkHandler(widget: StyledText) {
+
+        widget.addListener(SWT.MouseDown) { event ->
+            // It is up to the application to determine when and how a link
+            // should be activated.
+            // In this snippet links are activated on mouse down when the
+            // control key is held down
+            // if ((event.stateMask & SWT.MOD1) != 0) {
+            try {
+                val offset = widget.getOffsetAtLocation(Point(event.x, event.y))
+                val link = linkAt(offset)
+                if (link != null) {
+                    launchBrowser(link)
+                }
+
+            } catch (e: IllegalArgumentException) {
+                // no character under event.x, event.y
+            }
+        }
+    }
+
+    private fun linkAt(textIndex: Int): String? {
+        var span: IntArray
+        for ((key, value) in linksBySpan) {
+            span = key
+            if (span[0] <= textIndex && textIndex <= span[1]) {
+                return value
+            }
+        }
+        return null
+    }
+
+    private fun launchBrowser(link: String) {
+        try {
+            val browser = PlatformUI.getWorkbench().browserSupport.externalBrowser
+            browser.openURL(URL(link))
+        } catch (ex: Exception) {
+            ex.printStackTrace()
+        }
+    }
+
+    fun showOn(widget: StyledText) {
+        val text = buffer.toString()
+        widget.text = text
+        val ranges = ArrayList<StyleRange>()
+        var span: IntArray
+        for (i in headingSpans.indices) {
+            span = headingSpans[i]
+            ranges.add(StyleRange(span[0], span[1] - span[0], headingColor, background, SWT.BOLD))
+        }
+        for (spn in linksBySpan.keys) {
+            val style = StyleRange(spn[0], spn[1] - spn[0], headingColor, background, SWT.UNDERLINE_LINK)
+            style.underline = true
+            ranges.add(style)
+        }
+        val crStr = Character.toString(CR)
+        var sr: StyleRange
+
+        for (i in codeSpans.indices) {
+            span = codeSpans[i]
+            sr = StyleRange(codeStyle)
+            sr.start = span[0]
+            sr.length = span[1] - span[0]
+
+            val colorRanges = codeStyleExtractor.stylesFor(text, sr.start, sr.length, crStr)
+            ranges += colorRanges
+        }
+        // must be in order!
+        val styles = sort(ranges)
+        widget.styleRanges = styles
+    }
+
+    private fun sort(ranges: List<StyleRange>): Array<StyleRange> {
+        val styles = ranges.toTypedArray()
+        Arrays.sort(styles) { sr1, sr2 -> sr1.start - sr2.start }
+        return styles
+    }
+}

+ 19 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/FontBuilder.kt

@@ -0,0 +1,19 @@
+package com.alibaba.smartfox.eclipse.ui.pmd
+
+import org.eclipse.swt.graphics.Font
+import org.eclipse.swt.graphics.TextStyle
+import org.eclipse.swt.widgets.Display
+
+/**
+ * @author Brian Remedios
+ */
+class FontBuilder(val name: String, val size: Int, val style: Int, val colorIdx: Int = -1) {
+
+    fun build(display: Display): Font {
+        return Font(display, name, size, style)
+    }
+
+    fun style(display: Display): TextStyle {
+        return TextStyle(build(display), if (colorIdx < 0) null else display.getSystemColor(colorIdx), null)
+    }
+}

+ 54 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/StringArranger.kt

@@ -0,0 +1,54 @@
+package com.alibaba.smartfox.eclipse.ui.pmd
+
+import net.sourceforge.pmd.util.StringUtil
+import java.util.ArrayList
+
+/**
+ * @author Brian Remedios
+ */
+class StringArranger(private val indentString: String) {
+
+    fun withIndent(rawText: String): String {
+        return indentString + rawText
+    }
+
+    fun format(rawText: String): StringBuilder {
+
+        val sb = StringBuilder()
+        for (line in trimmedLinesIn(rawText)) {
+            sb.append(indentString)
+            sb.append(line).append(CR)
+        }
+
+        return sb
+    }
+
+    fun trimmedLinesIn(text: String): List<String> {
+
+        val lines = text.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+        if (lines.isEmpty()) {
+            return emptyList()
+        }
+
+        val lineSet = ArrayList<String>(lines.size)
+
+        var startLine = 0
+        while (startLine < lines.size && StringUtil.isEmpty(lines[startLine])) {
+            startLine++
+        }
+
+        var endLine = lines.size - 1
+        while (endLine >= 0 && StringUtil.isEmpty(lines[endLine])) {
+            endLine--
+        }
+
+        lines.mapTo(lineSet) {
+            it.trim { it <= ' ' }
+        }
+        return lineSet
+    }
+
+    companion object {
+        private val CR = '\n'
+    }
+}

+ 275 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/StyleExtractor.kt

@@ -0,0 +1,275 @@
+package com.alibaba.smartfox.eclipse.ui.pmd
+
+import net.sourceforge.pmd.util.StringUtil
+import org.eclipse.swt.SWT
+import org.eclipse.swt.custom.StyleRange
+import org.eclipse.swt.widgets.Display
+import java.util.ArrayList
+import java.util.LinkedList
+
+/**
+ * @author Brian Remedios
+ */
+open class StyleExtractor(private var syntaxData: SyntaxData?) {
+    private val commentOffsets: MutableList<IntArray>
+
+    init {
+        commentOffsets = LinkedList<IntArray>()
+    }
+
+    fun syntax(theSyntax: SyntaxData?) {
+        syntaxData = theSyntax
+    }
+
+    /**
+     * Refreshes the offsets for all multiline comments in the parent
+     * StyledText. The parent StyledText should call this whenever its text is
+     * modified. Note that this code doesn't ignore comment markers inside
+     * strings.
+
+     * @param text the text from the StyledText
+     */
+    fun refreshMultilineComments(text: String) {
+        // Clear any stored offsets
+        commentOffsets.clear()
+
+        if (syntaxData != null) {
+            // Go through all the instances of COMMENT_START
+            var pos = text.indexOf(syntaxData!!.multiLineCommentStart!!)
+            while (pos > -1) {
+                // offsets[0] holds the COMMENT_START offset
+                // and COMMENT_END holds the ending offset
+                val offsets = IntArray(2)
+                offsets[0] = pos
+
+                // Find the corresponding end comment.
+                pos = text.indexOf(syntaxData!!.multiLineCommentEnd!!, pos)
+
+                // If no corresponding end comment, use the end of the text
+                offsets[1] = if (pos == -1) text.length - 1 else pos + syntaxData!!.multiLineCommentEnd!!.length - 1
+                pos = offsets[1]
+                // Add the offsets to the collection
+                commentOffsets.add(offsets)
+                pos = text.indexOf(syntaxData!!.multiLineCommentStart!!, pos)
+            }
+        }
+    }
+
+    /**
+     * Checks to see if the specified section of text begins inside a multiline
+     * comment. Returns the index of the closing comment, or the end of the line
+     * if the whole line is inside the comment. Returns -1 if the line doesn't
+     * begin inside a comment.
+
+     * @param start the starting offset of the text
+     * @param length the length of the text
+     * @return int
+     */
+    private fun getBeginsInsideComment(start: Int, length: Int): Int {
+        // Assume section doesn't being inside a comment
+        var index = -1
+
+        // Go through the multiline comment ranges
+        var i = 0
+        val n = commentOffsets.size
+        while (i < n) {
+            val offsets = commentOffsets[i]
+
+            // If starting offset is past range, quit
+            if (offsets[0] > start + length) {
+                break
+            }
+            // Check to see if section begins inside a comment
+            if (offsets[0] <= start && offsets[1] >= start) {
+                // It does; determine if the closing comment marker is inside
+                // this section
+                index = if (offsets[1] > start + length) start + length
+                else offsets[1] + syntaxData!!.multiLineCommentEnd!!.length - 1
+            }
+            i++
+        }
+        return index
+    }
+
+    private fun isDefinedVariable(text: String): Boolean {
+        return StringUtil.isNotEmpty(text)
+    }
+
+    private fun atMultiLineCommentStart(text: String, position: Int): Boolean {
+        return text.indexOf(syntaxData!!.multiLineCommentStart!!, position) == position
+    }
+
+    private fun atStringStart(text: String, position: Int): Boolean {
+        return text.indexOf(syntaxData!!.stringStart!!, position) == position
+    }
+
+    private fun atVarnameReference(text: String, position: Int): Boolean {
+        return syntaxData!!.varnameReference != null && text.indexOf(syntaxData!!.varnameReference!!,
+                position) == position
+    }
+
+    private fun atSingleLineComment(text: String, position: Int): Boolean {
+        return syntaxData!!.comment != null && text.indexOf(syntaxData!!.comment!!, position) == position
+    }
+
+    private fun getKeywordEnd(lineText: String, start: Int): Int {
+
+        val length = lineText.length
+
+        val buf = StringBuilder(length)
+        var i = start
+
+        // Call any consecutive letters a word
+        while (i < length && Character.isLetter(lineText[i])) {
+            buf.append(lineText[i])
+            i++
+        }
+
+        return if (syntaxData!!.isKeyword(buf.toString())) i else 0 - i
+    }
+
+    /**
+     * Chop up the text into individual lines starting from offset and then
+     * determine the required styles for each. Ensures the offset is properly
+     * accounted for in each.
+
+     * @param text
+     * @param offset
+     * @param length
+     * @return
+     */
+    fun stylesFor(text: String, offset: Int, length: Int, lineSeparator: String): List<StyleRange> {
+
+        if (syntaxData == null) {
+            return emptyList()
+        }
+
+        val content = text.substring(offset, offset + length)
+        val lines = content.split(lineSeparator.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+
+        val styles = ArrayList<StyleRange>()
+
+        val separatorLength = lineSeparator.length
+
+        var currentOffset = offset
+
+        for (line in lines) {
+            val lineLength = line.length
+            val lineStyles = lineStylesFor(line, 0, lineLength)
+
+            for (sr in lineStyles) {
+                sr.start += currentOffset
+            }
+            styles.addAll(lineStyles)
+            currentOffset += lineLength + separatorLength
+        }
+
+        return styles
+    }
+
+    fun lineStylesFor(lineText: String, lineOffset: Int, length: Int): List<StyleRange> {
+
+        val styles = ArrayList<StyleRange>()
+
+        var start = 0
+
+        // Check if line begins inside a multiline comment
+        val mlIndex = getBeginsInsideComment(lineOffset, lineText.length)
+        if (mlIndex > -1) {
+            // Line begins inside multiline comment; create the range
+            styles.add(StyleRange(lineOffset, mlIndex - lineOffset, COMMENT_COLOR, COMMENT_BACKGROUND))
+            start = mlIndex
+        }
+        // Do punctuation, single-line comments, and keywords
+        while (start < length) {
+            // Check for multiline comments that begin inside this line
+            if (atMultiLineCommentStart(lineText, start)) {
+                // Determine where comment ends
+                var endComment = lineText.indexOf(syntaxData!!.multiLineCommentEnd!!, start)
+
+                // If comment doesn't end on this line, extend range to end of
+                // line
+                if (endComment == -1) {
+                    endComment = length
+                } else {
+                    endComment += syntaxData!!.multiLineCommentEnd!!.length
+                }
+                styles.add(StyleRange(lineOffset + start, endComment - start, COMMENT_COLOR, COMMENT_BACKGROUND))
+
+                start = endComment
+            } else if (atStringStart(lineText, start)) {
+                // Determine where comment ends
+                var endString = lineText.indexOf(syntaxData!!.stringEnd!!, start + 1)
+
+                // If string doesn't end on this line, extend range to end of
+                // line
+                if (endString == -1) {
+                    endString = length
+                } else {
+                    endString += syntaxData!!.stringEnd!!.length
+                }
+                styles.add(StyleRange(lineOffset + start, endString - start, STRING_COLOR, COMMENT_BACKGROUND))
+
+                start = endString
+            } else if (atSingleLineComment(lineText, start)) {
+                // line comments
+
+                styles.add(StyleRange(lineOffset + start, length - start, COMMENT_COLOR, COMMENT_BACKGROUND))
+                start = length
+            } else if (atVarnameReference(lineText, start)) {
+                // variable
+                // references
+
+                val buf = StringBuilder()
+                var i = start + syntaxData!!.varnameReference!!.length
+                // Call any consecutive letters a word
+                while (i < length && Character.isLetter(lineText[i])) {
+                    buf.append(lineText[i])
+                    i++
+                }
+
+                // See if the word is a variable
+                if (isDefinedVariable(buf.toString())) {
+                    // It's a keyword; create the StyleRange
+                    styles.add(StyleRange(lineOffset + start, i - start, REFERENCED_VAR_COLOR, null, SWT.BOLD))
+                }
+                // Move the marker to the last char (the one that wasn't a
+                // letter)
+                // so it can be retested in the next iteration through the loop
+                start = i
+            } else if (syntaxData!!.isPunctuation(lineText[start])) {
+                // Add range for punctuation
+                styles.add(StyleRange(lineOffset + start, 1, PUNCTUATION_COLOR, null))
+                ++start
+            } else if (Character.isLetter(lineText[start])) {
+
+                val kwEnd = getKeywordEnd(lineText, start)
+                // is a keyword
+
+                if (kwEnd > start) {
+                    styles.add(StyleRange(lineOffset + start, kwEnd - start, KEYWORD_COLOR, null))
+                }
+
+                // Move the marker to the last char (the one that wasn't a
+                // letter)
+                // so it can be retested in the next iteration through the loop
+                start = Math.abs(kwEnd)
+            } else {
+                ++start // It's nothing we're interested in; advance the marker
+            }// Check for punctuation
+        }
+
+        return styles
+    }
+
+    companion object {
+
+        private val COMMENT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN)
+        private val REFERENCED_VAR_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN)
+        private val UNREFERENCED_VAR_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW)
+        private val COMMENT_BACKGROUND = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)
+        private val PUNCTUATION_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)
+        private val KEYWORD_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_MAGENTA)
+        private val STRING_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE)
+    }
+}

+ 37 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/SyntaxData.kt

@@ -0,0 +1,37 @@
+package com.alibaba.smartfox.eclipse.ui.pmd
+
+/**
+ * This class contains information for syntax coloring and styling for an
+ * extension
+ */
+class SyntaxData(val extension: String) {
+
+    var varnameReference: String? = null
+    var stringStart: String? = null
+    var stringEnd: String? = null
+    private var keywords: Collection<String>? = null
+    private var punctuation: String? = null
+    var comment: String? = null
+    var multiLineCommentStart: String? = null
+    var multiLineCommentEnd: String? = null
+
+    fun matches(otherExtension: String): Boolean {
+        return extension == otherExtension
+    }
+
+    fun isKeyword(word: String): Boolean {
+        return keywords != null && keywords!!.contains(word)
+    }
+
+    fun isPunctuation(ch: Char): Boolean {
+        return punctuation != null && punctuation!!.indexOf(ch) >= 0
+    }
+
+    fun setKeywords(keywords: Collection<String>) {
+        this.keywords = keywords
+    }
+
+    fun setPunctuation(thePunctuationChars: String) {
+        punctuation = thePunctuationChars
+    }
+}

+ 94 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/SyntaxManager.kt

@@ -0,0 +1,94 @@
+package com.alibaba.smartfox.eclipse.ui.pmd
+
+import org.eclipse.swt.custom.StyledText
+import org.eclipse.swt.events.ModifyListener
+import java.util.HashSet
+import java.util.Hashtable
+import java.util.MissingResourceException
+import java.util.ResourceBundle
+import java.util.StringTokenizer
+
+/**
+ * This class manages the syntax coloring and styling data
+ */
+object SyntaxManager {
+
+    private val syntaxByExtension = Hashtable<String, SyntaxData>()
+
+    fun adapt(codeField: StyledText, languageCode: String, oldListener: ModifyListener?): ModifyListener? {
+
+        if (oldListener != null) {
+            codeField.removeModifyListener(oldListener)
+        }
+
+        val sd = SyntaxManager.getSyntaxData(languageCode) ?: return null
+
+        val blsl = BasicLineStyleListener(sd)
+        codeField.addLineStyleListener(blsl)
+
+        val ml = ModifyListener {
+            blsl.refreshMultilineComments(codeField.text)
+            codeField.redraw()
+        }
+        codeField.addModifyListener(ml)
+
+        return ml
+    }
+
+    /**
+     * Gets the syntax data for an extension
+     */
+    @Synchronized fun getSyntaxData(extension: String): SyntaxData? {
+        // Check in cache
+        var sd: SyntaxData? = syntaxByExtension[extension]
+        if (sd == null) {
+            // Not in cache; load it and put in cache
+            sd = loadSyntaxData(extension)
+            if (sd != null) {
+                syntaxByExtension.put(sd.extension, sd)
+            }
+        }
+        return sd
+    }
+
+    /**
+     * Loads the syntax data for an extension
+     * @return SyntaxData
+     */
+    private fun loadSyntaxData(filename: String): SyntaxData? {
+        var sd: SyntaxData? = null
+        try {
+            val rb = ResourceBundle.getBundle("/syntax/$filename")
+            sd = SyntaxData(filename)
+
+            sd.stringStart = rb.getString("stringstart")
+            sd.stringEnd = rb.getString("stringend")
+            sd.multiLineCommentStart = rb.getString("multilinecommentstart")
+            sd.multiLineCommentEnd = rb.getString("multilinecommentend")
+
+            // Load the keywords
+            val keywords = HashSet<String>()
+            val st = StringTokenizer(rb.getString("keywords"), " ")
+            while (st.hasMoreTokens()) {
+                keywords.add(st.nextToken())
+            }
+            sd.setKeywords(keywords)
+
+            // Load the punctuation
+            sd.setPunctuation(rb.getString("punctuation"))
+
+            if (rb.containsKey("comment")) {
+                sd.comment = rb.getString("comment")
+            }
+
+            if (rb.containsKey("varnamedelimiter")) {
+                sd.varnameReference = rb.getString("varnamedelimiter")
+            }
+
+        } catch (e: MissingResourceException) {
+            // Ignore
+        }
+
+        return sd
+    }
+}

+ 361 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/util/CleanUps.kt

@@ -0,0 +1,361 @@
+// =====================================================================
+//
+// Copyright (C) 2012 - 2016, Philip Graf
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// which accompanies this distribution, and is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// =====================================================================
+package com.alibaba.smartfox.eclipse.util
+
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import org.eclipse.core.filebuffers.FileBuffers
+import org.eclipse.core.filebuffers.ITextFileBuffer
+import org.eclipse.core.filebuffers.LocationKind
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.runtime.Assert
+import org.eclipse.core.runtime.CoreException
+import org.eclipse.core.runtime.IProgressMonitor
+import org.eclipse.core.runtime.IStatus
+import org.eclipse.core.runtime.NullProgressMonitor
+import org.eclipse.core.runtime.Status
+import org.eclipse.jdt.core.ICompilationUnit
+import org.eclipse.jdt.core.IJavaProject
+import org.eclipse.jdt.core.JavaCore
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants
+import org.eclipse.jdt.internal.corext.fix.CleanUpRefactoring
+import org.eclipse.jdt.internal.corext.fix.FixMessages
+import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser
+import org.eclipse.jdt.internal.ui.JavaPlugin
+import org.eclipse.jdt.internal.ui.actions.ActionUtil
+import org.eclipse.jdt.internal.ui.fix.MapCleanUpOptions
+import org.eclipse.jdt.ui.SharedASTProvider
+import org.eclipse.jdt.ui.cleanup.CleanUpContext
+import org.eclipse.jdt.ui.cleanup.CleanUpOptions
+import org.eclipse.jdt.ui.cleanup.ICleanUp
+import org.eclipse.jface.text.BadLocationException
+import org.eclipse.jface.text.IDocument
+import org.eclipse.jface.text.IDocumentExtension4
+import org.eclipse.jface.window.Window
+import org.eclipse.ltk.core.refactoring.Change
+import org.eclipse.ltk.core.refactoring.CompositeChange
+import org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes
+import org.eclipse.ltk.core.refactoring.NullChange
+import org.eclipse.ltk.core.refactoring.PerformChangeOperation
+import org.eclipse.ltk.core.refactoring.RefactoringCore
+import org.eclipse.ltk.core.refactoring.RefactoringStatus
+import org.eclipse.ltk.core.refactoring.TextFileChange
+import org.eclipse.ltk.ui.refactoring.RefactoringUI
+import org.eclipse.text.edits.MalformedTreeException
+import org.eclipse.text.edits.TextEdit
+import org.eclipse.text.edits.UndoEdit
+import org.eclipse.ui.PlatformUI
+import java.util.ArrayList
+import java.util.HashMap
+import java.util.LinkedList
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/15
+ */
+object CleanUps {
+
+    private val WARNING_VALUE = "warning"
+    private val ERROR_VALUE = "error"
+
+    val cleanUpSettings = mapOf(CleanUpConstants.ADD_MISSING_ANNOTATIONS to CleanUpOptions.TRUE,
+            CleanUpConstants.CONTROL_STATMENTS_USE_BLOCKS_ALWAYS to CleanUpOptions.TRUE,
+            CleanUpConstants.ADD_MISSING_ANNOTATIONS_OVERRIDE to CleanUpOptions.TRUE,
+            CleanUpConstants.CONTROL_STATEMENTS_USE_BLOCKS to CleanUpOptions.TRUE,
+            CleanUpConstants.ADD_MISSING_ANNOTATIONS_OVERRIDE_FOR_INTERFACE_METHOD_IMPLEMENTATION to
+                    CleanUpOptions.TRUE)
+
+    fun fix(file: IFile, monitor: IProgressMonitor) {
+        val compilationUnit = JavaCore.createCompilationUnitFrom(file) ?: return
+        doCleanUp(compilationUnit, monitor)
+    }
+
+    @Throws(CoreException::class) fun doCleanUp(unit: ICompilationUnit, monitor: IProgressMonitor) {
+
+        monitor.beginTask("Fix", IProgressMonitor.UNKNOWN)
+
+        if (!ActionUtil.isOnBuildPath(unit)) return
+        val result = CompositeChange(FixMessages.CleanUpPostSaveListener_SaveAction_ChangeName)
+        val undoEdits = LinkedList<UndoEdit>()
+        val oldFileValue = unit.resource.modificationStamp
+        val oldDocValue = getDocumentStamp(unit.resource as IFile, monitor)
+        val manager = RefactoringCore.getUndoManager()
+        var success = false
+
+        try {
+            manager.aboutToPerformChange(result)
+            success = doCleanUp(unit, monitor, result, undoEdits)
+        } finally {
+            manager.changePerformed(result, success)
+        }
+
+        if (undoEdits.size > 0) {
+            val undoEditArray = undoEdits.toTypedArray()
+            val undo = CleanUpSaveUndo(result.name, unit.resource as IFile, undoEditArray, oldDocValue, oldFileValue)
+            undo.initializeValidationData(NullProgressMonitor())
+            manager.addUndo(result.name, undo)
+        }
+    }
+
+    @Throws(CoreException::class) private fun getDocumentStamp(file: IFile, monitor: IProgressMonitor): Long {
+        val manager = FileBuffers.getTextFileBufferManager()
+        val path = file.fullPath
+
+        monitor.beginTask("", 2)
+
+        var buffer: ITextFileBuffer? = null
+        try {
+            manager.connect(path, LocationKind.IFILE, monitor)
+            buffer = manager.getTextFileBuffer(path, LocationKind.IFILE)
+            val document = buffer!!.document
+
+            if (document is IDocumentExtension4) {
+                return document.modificationStamp
+            } else {
+                return file.modificationStamp
+            }
+        } finally {
+            if (buffer != null) manager.disconnect(path, LocationKind.IFILE, monitor)
+            monitor.done()
+        }
+    }
+
+    private fun doCleanUp(unit: ICompilationUnit, monitor: IProgressMonitor, result: CompositeChange,
+            undoEdits: LinkedList<UndoEdit>): Boolean {
+        val cleanUps = JavaPlugin.getDefault().cleanUpRegistry.createCleanUps(
+                setOf("org.eclipse.jdt.ui.cleanup.java50", "org.eclipse.jdt.ui.cleanup.control_statements"))
+        val preCondition = RefactoringStatus()
+        val postCondition = RefactoringStatus()
+        cleanUps.forEach { cleanUp ->
+            cleanUp.setOptions(MapCleanUpOptions(cleanUpSettings))
+
+            preCondition.merge(cleanUp.checkPreConditions(unit.javaProject, arrayOf(unit), monitor))
+
+            val options = HashMap<String, String>(cleanUp.requirements.compilerOptions ?: emptyMap())
+
+            var ast = CleanUps.createAst(unit, options, monitor)
+            if (cleanUp.requirements.requiresAST()) {
+                ast = createAst(unit, options, monitor)
+            }
+
+            val context = CleanUpContext(unit, ast)
+
+            val undoneCleanUps = ArrayList<ICleanUp>()
+            val change = CleanUpRefactoring.calculateChange(context, arrayOf(cleanUp), undoneCleanUps, null)
+
+            postCondition.merge(cleanUp.checkPostConditions(monitor))
+            if (showStatus(postCondition) != Window.OK) {
+                return@doCleanUp false
+            }
+
+            if (change == null) {
+                return@forEach
+            }
+            result.add(change)
+
+            change.initializeValidationData(NullProgressMonitor())
+
+            val performChangeOperation = PerformChangeOperation(change)
+            performChangeOperation.setSchedulingRule(unit.schedulingRule)
+            performChangeOperation.run(monitor)
+            performChangeOperation.undoChange
+            undoEdits.addFirst(change.undoEdit)
+        }
+
+        return true
+    }
+
+    private fun showStatus(status: RefactoringStatus): Int {
+        if (!status.hasError()) return Window.OK
+
+        val shell = PlatformUI.getWorkbench().activeWorkbenchWindow.shell
+
+        val dialog = RefactoringUI.createRefactoringStatusDialog(status, shell, "", false)
+        return dialog.open()
+    }
+
+    private fun createAst(unit: ICompilationUnit, cleanUpOptions: Map<String, String>,
+            monitor: IProgressMonitor): CompilationUnit {
+        val project = unit.javaProject
+        if (compatibleOptions(project, cleanUpOptions)) {
+            val ast = SharedASTProvider.getAST(unit, SharedASTProvider.WAIT_NO, monitor)
+            if (ast != null) return ast
+        }
+
+        val parser = CleanUpRefactoring.createCleanUpASTParser()
+        parser.setSource(unit)
+
+        val compilerOptions = RefactoringASTParser.getCompilerOptions(unit.javaProject)
+        compilerOptions.putAll(cleanUpOptions)
+        parser.setCompilerOptions(compilerOptions)
+
+        return parser.createAST(monitor) as CompilationUnit
+    }
+
+    private fun compatibleOptions(project: IJavaProject, cleanUpOptions: Map<String, String>): Boolean {
+        if (cleanUpOptions.isEmpty()) {
+            return true
+        }
+
+        val projectOptions = project.getOptions(true)
+
+        return !cleanUpOptions.keys.any {
+            val projectOption = projectOptions[it]?.toString()
+            val cleanUpOption = cleanUpOptions[it]?.toString()
+            !strongerEquals(projectOption, cleanUpOption)
+        }
+    }
+
+    private fun strongerEquals(projectOption: String?, cleanUpOption: String?): Boolean {
+        if (projectOption == null) return false
+
+        if (ERROR_VALUE == cleanUpOption) {
+            return ERROR_VALUE == projectOption
+        } else if (WARNING_VALUE == cleanUpOption) {
+            return ERROR_VALUE == projectOption || WARNING_VALUE == projectOption
+        }
+
+        return false
+    }
+
+    private class CleanUpSaveUndo(name: String, private val fFile: IFile, private val fUndos: Array<UndoEdit>,
+            private val fDocumentStamp: Long, private val fFileStamp: Long) : TextFileChange(name,
+            fFile) {
+
+        init {
+            Assert.isNotNull(fUndos)
+        }
+
+        public override fun needsSaving(): Boolean {
+            return true
+        }
+
+        @Throws(CoreException::class) override fun perform(monitor: IProgressMonitor?): Change {
+            val pm = monitor ?: NullProgressMonitor()
+            if (isValid(pm).hasFatalError()) return NullChange()
+
+            val manager = FileBuffers.getTextFileBufferManager()
+            pm.beginTask("", 2)
+            var buffer: ITextFileBuffer? = null
+
+            try {
+                manager.connect(fFile.fullPath, LocationKind.IFILE, pm)
+                buffer = manager.getTextFileBuffer(fFile.fullPath, LocationKind.IFILE)
+
+                val document = buffer!!.document
+                val oldFileValue = fFile.modificationStamp
+                val undoEditCollector = LinkedList<UndoEdit>()
+                val oldDocValue = LongArray(1)
+                val setContentStampSuccess = booleanArrayOf(false)
+
+                if (!buffer.isSynchronizationContextRequested) {
+                    performEdit(document, oldFileValue, undoEditCollector, oldDocValue, setContentStampSuccess)
+
+                } else {
+                    val fileBufferManager = FileBuffers.getTextFileBufferManager()
+
+                    class UIRunnable : Runnable {
+                        var fDone: Boolean = false
+                        var fException: Exception? = null
+
+                        override fun run() {
+                            synchronized(this) {
+                                try {
+                                    performEdit(document, oldFileValue, undoEditCollector, oldDocValue,
+                                            setContentStampSuccess)
+                                } catch (e: BadLocationException) {
+                                    fException = e
+                                } catch (e: MalformedTreeException) {
+                                    fException = e
+                                } catch (e: CoreException) {
+                                    fException = e
+                                } finally {
+                                    fDone = true
+                                    (this as Object).notifyAll()
+                                }
+                            }
+                        }
+                    }
+
+                    val runnable = UIRunnable()
+
+                    synchronized(runnable) {
+                        fileBufferManager.execute(runnable)
+                        while (!runnable.fDone) {
+                            try {
+                                (runnable as Object).wait(500)
+                            } catch (x: InterruptedException) {
+                            }
+
+                        }
+                    }
+
+                    if (runnable.fException != null) {
+                        if (runnable.fException is BadLocationException) {
+                            throw runnable.fException as BadLocationException
+                        } else if (runnable.fException is MalformedTreeException) {
+                            throw runnable.fException as MalformedTreeException
+                        } else if (runnable.fException is CoreException) {
+                            throw runnable.fException as CoreException
+                        }
+                    }
+                }
+
+                buffer.commit(pm, false)
+                if (!setContentStampSuccess[0]) {
+                    fFile.revertModificationStamp(fFileStamp)
+                }
+
+                return CleanUpSaveUndo(name, fFile, undoEditCollector.toTypedArray(), oldDocValue[0], oldFileValue)
+            } catch (e: BadLocationException) {
+                throw wrapBadLocationException(e)
+            } finally {
+                if (buffer != null) manager.disconnect(fFile.fullPath, LocationKind.IFILE, pm)
+            }
+        }
+
+        @Throws(MalformedTreeException::class, BadLocationException::class,
+                CoreException::class) private fun performEdit(document: IDocument, oldFileValue: Long,
+                editCollector: LinkedList<UndoEdit>,
+                oldDocValue: LongArray,
+                setContentStampSuccess: BooleanArray) {
+            if (document is IDocumentExtension4) {
+                oldDocValue[0] = document.modificationStamp
+            } else {
+                oldDocValue[0] = oldFileValue
+            }
+
+            // perform the changes
+            fUndos.map { it.apply(document, TextEdit.CREATE_UNDO) }.forEach { editCollector.addFirst(it) }
+
+            if (document is IDocumentExtension4 && fDocumentStamp != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) {
+                try {
+                    document.replace(0, 0, "", fDocumentStamp)
+                    setContentStampSuccess[0] = true
+                } catch (e: BadLocationException) {
+                    throw wrapBadLocationException(e)
+                }
+
+            }
+        }
+    }
+
+    private fun wrapBadLocationException(e: BadLocationException): CoreException {
+        var message: String? = e.message
+        if (message == null) message = "BadLocationException"
+        return CoreException(
+                Status(IStatus.ERROR, SmartfoxActivator.PLUGIN_ID, IRefactoringCoreStatusCodes.BAD_LOCATION, message,
+                        e))
+    }
+
+}

+ 135 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/util/MarkerUtil.kt

@@ -0,0 +1,135 @@
+// =====================================================================
+//
+// Copyright (C) 2012 - 2016, Philip Graf
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// which accompanies this distribution, and is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// =====================================================================
+package com.alibaba.smartfox.eclipse.util
+
+import com.alibaba.smartfox.eclipse.QuickFixGenerator
+import com.alibaba.smartfox.eclipse.SmartfoxActivator
+import com.google.common.io.Files
+import net.sourceforge.pmd.Rule
+import net.sourceforge.pmd.RulePriority
+import net.sourceforge.pmd.RuleViolation
+import org.eclipse.core.resources.IFile
+import org.eclipse.core.resources.IMarker
+import org.eclipse.core.resources.IProject
+import org.eclipse.core.resources.IResource
+import org.eclipse.core.runtime.CoreException
+import org.eclipse.jface.text.BadLocationException
+import org.eclipse.jface.text.Document
+import org.eclipse.ui.IMarkerResolution
+import java.nio.charset.Charset
+
+/**
+ * @author caikang
+ * @date 2017/06/08
+ */
+object MarkerUtil {
+
+    private val PMD_TAB_SIZE = 8
+
+    private val MARKER_TYPE = "${SmartfoxActivator.PLUGIN_ID}.p3cMarker"
+
+    @Throws(CoreException::class)
+    fun removeAllMarkers(file: IFile) {
+        try {
+            if (file.exists()) {
+                file.deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_ZERO)
+            }
+        } catch (e: Exception) {
+            SmartfoxActivator.instance.logError(e.message ?: "", e)
+        }
+    }
+
+    @Throws(CoreException::class)
+    fun removeAllMarkers(project: IProject) {
+        project.deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_INFINITE)
+    }
+
+    @Throws(CoreException::class)
+    fun addMarker(file: IFile, violation: RuleViolation): IMarker {
+        val marker = file.createMarker(MARKER_TYPE)
+        marker.setAttribute(IMarker.MESSAGE, violation.description)
+        val severity = when (violation.rule.priority) {
+            RulePriority.HIGH -> IMarker.SEVERITY_ERROR
+            RulePriority.MEDIUM_HIGH -> IMarker.SEVERITY_WARNING
+            else -> IMarker.SEVERITY_INFO
+        }
+        marker.setRule(violation.rule.name)
+        marker.setAttribute(IMarker.SEVERITY, severity)
+        marker.setAttribute(IMarker.LINE_NUMBER, Math.max(violation.beginLine, 0))
+        val range = getAbsoluteRange(file, violation)
+        val start = Math.max(range.start, 0)
+        marker.setAttribute(IMarker.CHAR_START, start)
+        val end = Math.max(range.end, 0)
+        marker.setAttribute(IMarker.CHAR_END, end)
+        return marker
+    }
+
+
+    fun getAbsoluteRange(file: IFile, violation: RuleViolation): Range {
+        val content = Files.toString(file.rawLocation.toFile(), Charset.forName(file.charset))
+        try {
+            return calculateAbsoluteRange(content, violation)
+        } catch (e: BadLocationException) {
+            return Range(0, 0)
+        }
+    }
+
+    @Throws(BadLocationException::class) private fun calculateAbsoluteRange(content: String,
+            violation: RuleViolation): Range {
+        val document = Document(content)
+
+        // violation line and column start at one, the marker's start and end positions at zero
+        val start = getAbsolutePosition(content, document.getLineOffset(violation.beginLine - 1), violation.beginColumn)
+        val end = getAbsolutePosition(content, document.getLineOffset(violation.endLine - 1), violation.endColumn)
+
+        // for some rules PMD creates violations with the end position before the start position
+        val range = if (start <= end) {
+            Range(start - 1, end)
+        } else {
+            Range(end - 1, start)
+        }
+
+        return range
+    }
+
+    private fun getAbsolutePosition(content: String, lineOffset: Int, pmdCharOffset: Int): Int {
+        var pmdCharCounter = 0
+        var absoluteOffset = lineOffset
+        while (pmdCharCounter < pmdCharOffset) {
+            if (absoluteOffset < content.length) {
+                val c = content[absoluteOffset]
+                if (c == '\t') {
+                    pmdCharCounter = (pmdCharCounter / PMD_TAB_SIZE + 1) * PMD_TAB_SIZE
+                } else {
+                    pmdCharCounter++
+                }
+            } else {
+                break
+            }
+            absoluteOffset++
+        }
+        return absoluteOffset
+    }
+}
+
+fun IMarker.setRule(rule: String) {
+    this.setAttribute("rule", rule)
+}
+
+fun IMarker.getRule(): Rule {
+    return SmartfoxActivator.instance.getRule(this.getAttribute("rule") as String)
+}
+
+fun IMarker.getResolution(): IMarkerResolution? {
+    return QuickFixGenerator.quickFixes[getRule().name]
+}
+
+data class Range(val start: Int, val end: Int)

+ 23 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/messages/P3cBundle.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+    <entry key="com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler">阿里编码规约扫描</entry>
+
+    <entry key="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.text.cur_zh">切换语言至英文(English)</entry>
+    <entry key="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.text.cur_en">切换语言至中文</entry>
+    <entry key="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.success.en">切换到English成功,是否重启</entry>
+    <entry key="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.success.zh">切换到中文成功,是否重启</entry>
+
+
+    <entry key="rule.standalone.MissingOverrideAnnotationRule.msg"><![CDATA[所有的覆写方法,必须加@Override注解。]]></entry>
+    <entry key="rule.standalone.MissingOverrideAnnotationRule.desc"><![CDATA[反例:getObject()与get0bject()的问题。一个是字母的O,一个是数字的0,加@Override可以准确判断是否覆盖成功。另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错。]]></entry>
+    <entry key="rule.standalone.MissingOverrideAnnotationRule.error"><![CDATA[方法缺少 '@Override' 注解]]></entry>
+    <entry key="rule.standalone.AvoidAccessStaticViaInstanceRule.msg"><![CDATA[避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。]]></entry>
+    <entry key="rule.standalone.AvoidUseDeprecationRule.msg"><![CDATA[不能使用过时的类或方法。]]></entry>
+    <entry key="rule.standalone.AvoidUseDeprecationRule.desc"><![CDATA[说明:java.net.URLDecoder 中的方法decode(String encodeStr) 这个方法已经过时,应该使用双参数decode(String source, String encode)。接口提供方既然明确是过时接口,那么有义务同时提供新的接口;作为调用方来说,有义务去考证过时方法的新实现是什么。]]></entry>
+    <entry key="rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.msg"><![CDATA[Map/Set的key为自定义对象时,必须重写hashCode和equals。]]></entry>
+    <entry key="rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.desc"><![CDATA[关于hashCode和equals的处理,遵循如下规则:
+ 1) 只要重写equals,就必须重写hashCode。
+ 2) 因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。
+ 3) 如果自定义对象做为Map的键,那么必须重写hashCode和equals。]]></entry>
+</properties>

+ 25 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/messages/P3cBundle_en.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+    <entry key="com.alibaba.smartfox.eclipse.handler.CodeAnalysisHandler">Alibaba Coding Guidelines Analyze</entry>
+    <entry key="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.text.cur_zh">Switch language to English</entry>
+    <entry key="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.text.cur_en">Switch language to Chinese</entry>
+
+    <entry key="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.success.en">Switch language to English success,restart?</entry>
+    <entry key="com.alibaba.smartfox.eclipse.handler.SwitchLanguageHandler.success.zh">Switch language to Chinese success,restart?</entry>
+
+    <entry key="rule.standalone.MissingOverrideAnnotationRule.msg"><![CDATA[An overridden method from an interface or abstract class must be marked with @Override annotation.]]></entry>
+    <entry key="rule.standalone.MissingOverrideAnnotationRule.desc"><![CDATA[
+    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>
+    <entry key="rule.standalone.MissingOverrideAnnotationRule.error"><![CDATA[Method missing '@Override' annotation]]></entry>
+    <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>
+
+    <entry key="rule.standalone.AvoidUseDeprecationRule.msg"><![CDATA[Using a deprecated class or method is prohibited.]]></entry>
+    <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>
+    <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>
+    <entry key="rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.desc"><![CDATA[The usage of hashCode and equals should follow:
+ 1) Override hashCode if equals is overridden.
+ 2) These two methods must be overridden for Set since they are used to ensure that no duplicate object will be inserted in Set.
+ 3) These two methods must be overridden if self-defined object is used as the key of Map.
+Note: String can be used as the key of Map since these two methods have been rewritten.]]></entry>
+</properties>

+ 17 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/rulesets/java/ali-pmd.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+
+<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="alibaba-pmd"
+         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
+         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
+    <rule ref="rulesets/java/ali-concurrent.xml"/>
+    <rule ref="rulesets/java/ali-comment.xml"/>
+    <rule ref="rulesets/java/ali-naming.xml"/>
+    <rule ref="rulesets/java/ali-constant.xml"/>
+    <rule ref="rulesets/java/ali-other.xml"/>
+    <rule ref="rulesets/java/ali-flowcontrol.xml"/>
+    <rule ref="rulesets/java/ali-oop.xml"/>
+    <rule ref="rulesets/java/ali-orm.xml"/>
+    <rule ref="rulesets/java/ali-exception.xml"/>
+    <rule ref="rulesets/java/ali-set.xml"/>
+    <rule ref="rulesets/java/ali-ruleOnEclipse.xml"/>
+</ruleset>

+ 42 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/rulesets/java/ali-ruleOnEclipse.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+
+<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="AlibabaRuleOnEclipse"
+         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
+         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
+
+    <rule name="MissingOverrideAnnotationRule" message="rule.standalone.MissingOverrideAnnotationRule.msg"
+          class="com.alibaba.smartfox.eclipse.pmd.rule.MissingOverrideAnnotationRule">
+        <description>rule.standalone.MissingOverrideAnnotationRule.desc</description>
+        <priority>1</priority>
+
+        <example>
+            <![CDATA[
+    /**
+     * @author caikang
+     * @date 2016/12/24
+     */
+    public class MissingOverrideAnnotationRule extends AbstractEclipseRule {
+        @Override
+        public Object visit(ASTCompilationUnit node, Object data) {
+            return super.visit(node, data);
+        }
+    }
+]]>
+        </example>
+    </rule>
+    <rule name="AvoidAccessStaticViaInstanceRule" message="rule.standalone.AvoidAccessStaticViaInstanceRule.msg"
+          class="com.alibaba.smartfox.eclipse.pmd.rule.AvoidAccessStaticViaInstanceRule">
+        <priority>1</priority>
+    </rule>
+    <rule name="AvoidUseDeprecationRule" message="rule.standalone.AvoidUseDeprecationRule.msg"
+          class="com.alibaba.smartfox.eclipse.pmd.rule.AvoidUseDeprecationRule">
+        <description>rule.standalone.AvoidUseDeprecationRule.desc</description>
+        <priority>2</priority>
+    </rule>
+
+    <rule name="MapOrSetKeyShouldOverrideHashCodeEqualsRule" message="rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.msg"
+          class="com.alibaba.smartfox.eclipse.pmd.rule.MapOrSetKeyShouldOverrideHashCodeEqualsRule">
+        <description>rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.desc</description>
+        <priority>2</priority>
+    </rule>
+</ruleset>

+ 8 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/syntax/java.properties

@@ -0,0 +1,8 @@
+# This file contains the syntax data for .java files
+comment=//
+stringstart="
+stringend="
+multilinecommentstart=/*
+multilinecommentend=*/
+punctuation=(){};:?<>=+-*/&|~!%.[]
+keywords=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

+ 10 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.updatesite/category.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+   <description url="https://p3c.alibaba.com/plugin/eclipse/update">
+      Alibaba Java Coding Guidelines
+   </description>
+   <feature id="com.alibaba.smartfox.eclipse.feature" version="0.0.0">
+      <category name="Smartfox"/>
+   </feature>
+   <category-def name="Smartfox" label="Smartfox Eclipse Plugin"/>
+</site>

+ 13 - 0
环境配置/技术规范/p3c/eclipse-plugin/com.alibaba.smartfox.eclipse.updatesite/pom.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.alibaba.smartfox.eclipse</groupId>
+    <artifactId>smartfox-eclipse</artifactId>
+    <version>2.0.1-SNAPSHOT</version>
+  </parent>
+  <artifactId>com.alibaba.smartfox.eclipse.updatesite</artifactId>
+  <packaging>eclipse-repository</packaging>
+  <inceptionYear>2017</inceptionYear>
+</project>

BIN
环境配置/技术规范/p3c/eclipse-plugin/doc/images/analyze_result.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/doc/images/eclipse_analyze.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/doc/images/eclipse_switch_language.png


BIN
环境配置/技术规范/p3c/eclipse-plugin/doc/images/install.png


+ 198 - 0
环境配置/技术规范/p3c/eclipse-plugin/pom.xml

@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.alibaba.smartfox.eclipse</groupId>
+    <artifactId>smartfox-eclipse</artifactId>
+    <version>2.0.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <inceptionYear>2017</inceptionYear>
+    <properties>
+        <tycho.version>1.0.0</tycho.version>
+        <tycho-extras.version>${tycho.version}</tycho-extras.version>
+        <eclipse-repo.url>http://download.eclipse.org/releases/neon</eclipse-repo.url>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <ajdt-eclipse-repo.url>http://download.eclipse.org/tools/ajdt/46/dev/update</ajdt-eclipse-repo.url>
+        <kotlin.version>1.3.30</kotlin.version>
+        <eclipse-release>juno</eclipse-release>
+    </properties>
+    <modules>
+        <module>com.alibaba.smartfox.eclipse.plugin</module>
+        <module>com.alibaba.smartfox.eclipse.feature</module>
+        <module>com.alibaba.smartfox.eclipse.updatesite</module>
+    </modules>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.11</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.jetbrains.kotlin</groupId>
+                <artifactId>kotlin-stdlib-jdk8</artifactId>
+                <version>${kotlin.version}</version>
+                <scope>compile</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    <repositories>
+        <repository>
+            <id>juno</id>
+            <layout>p2</layout>
+            <url>http://mirrors.ustc.edu.cn/eclipse/releases/juno/</url>
+        </repository>
+        <repository>
+            <id>sonatype-nexus-snapshots</id>
+            <name>Sonatype Nexus Snapshots</name>
+            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.eclipse.tycho</groupId>
+                <artifactId>tycho-maven-plugin</artifactId>
+                <version>${tycho.version}</version>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.eclipse.tycho</groupId>
+                <artifactId>target-platform-configuration</artifactId>
+                <configuration>
+                    <environments>
+                        <environment>
+                            <os>linux</os>
+                            <ws>gtk</ws>
+                            <arch>x86</arch>
+                        </environment>
+                        <environment>
+                            <os>linux</os>
+                            <ws>gtk</ws>
+                            <arch>x86_64</arch>
+                        </environment>
+                        <environment>
+                            <os>win32</os>
+                            <ws>win32</ws>
+                            <arch>x86</arch>
+                        </environment>
+                        <environment>
+                            <os>win32</os>
+                            <ws>win32</ws>
+                            <arch>x86_64</arch>
+                        </environment>
+                        <environment>
+                            <os>macosx</os>
+                            <ws>cocoa</ws>
+                            <arch>x86_64</arch>
+                        </environment>
+                    </environments>
+                </configuration>
+            </plugin>
+        </plugins>
+
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.eclipse.tycho</groupId>
+                    <artifactId>target-platform-configuration</artifactId>
+                    <version>${tycho.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho</groupId>
+                    <artifactId>tycho-compiler-plugin</artifactId>
+                    <version>${tycho.version}</version>
+                    <configuration>
+                        <compilerVersion>1.8</compilerVersion>
+                        <compilerArguments>
+                            <inlineJSR/>
+                            <enableJavadoc/>
+                            <encoding>UTF-8</encoding>
+                        </compilerArguments>
+                        <compilerArgument>-err:-forbidden</compilerArgument>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>aspectj-maven-plugin</artifactId>
+                    <version>${aspectj.plugin.version}</version>
+                    <dependencies>
+                        <dependency>
+                            <groupId>org.aspectj</groupId>
+                            <artifactId>aspectjtools</artifactId>
+                            <version>${aspectj.version}</version>
+                        </dependency>
+                    </dependencies>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho</groupId>
+                    <artifactId>tycho-packaging-plugin</artifactId>
+                    <version>${tycho.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho</groupId>
+                    <artifactId>tycho-surefire-plugin</artifactId>
+                    <version>${tycho.version}</version>
+                    <configuration>
+                        <testFailureIgnore>true</testFailureIgnore>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho</groupId>
+                    <artifactId>tycho-source-plugin</artifactId>
+                    <version>${tycho.version}</version>
+                    <configuration>
+                        <strictSrcIncludes>false</strictSrcIncludes>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho</groupId>
+                    <artifactId>tycho-p2-director-plugin</artifactId>
+                    <version>${tycho.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho</groupId>
+                    <artifactId>tycho-p2-repository-plugin</artifactId>
+                    <version>${tycho.version}</version>
+                    <configuration>
+                        <finalName>smartfox-eclipse-plugin</finalName>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho.extras</groupId>
+                    <artifactId>tycho-source-feature-plugin</artifactId>
+                    <version>${tycho-extras.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho.extras</groupId>
+                    <artifactId>tycho-custom-bundle-plugin</artifactId>
+                    <version>${tycho-extras.version}</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.eclipse.tycho</groupId>
+                    <artifactId>tycho-p2-plugin</artifactId>
+                    <version>${tycho.version}</version>
+                    <configuration>
+                        <baselineMode>warn</baselineMode>
+                        <baselineReplace>none</baselineReplace>
+                        <baselineRepositories>
+                            <repository>
+                                <url>http://download.eclipse.org/eclipse/updates/4.4</url>
+                            </repository>
+                        </baselineRepositories>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+</project>

+ 94 - 0
环境配置/技术规范/p3c/idea-plugin/.gitignore

@@ -0,0 +1,94 @@
+# Gradle
+build
+.gradle
+
+testdata/
+# Java gitignore #
+.class
+.log
+
+# Package Files #
+
+*.war
+*.ear
+
+#hsf files
+configuration
+
+# maven gitignore#
+target/**
+
+.svn/
+
+# intelliJ.gitignore #
+.idea
+*.iml
+*.ipr
+*.iws
+
+# Eclipse git ignore#
+*.pydevproject
+.project
+.metadata
+bin/**
+*/bin/**
+tmp/**
+tmp/**/*
+configuration/**
+*.tmp
+*.bak
+*.orig
+*.swp
+*~.nib
+.classpath
+.settings/
+.loadpath
+.fileTable*
+.cache
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+#log
+*.log
+*.log.*
+
+# Windows Thumbs.db
+*.db
+
+# OSX
+.DS_Store
+
+# sass gitignore#
+.sass-cache
+.idea
+
+# tcc_coverage
+coverage.ec
+
+
+
+config.client.*
+
+temp/
+*.pid
+*.orig
+
+hsf.configuration/
+
+# code coverage report
+*.ec
+
+#hsf test
+*.instance
+out
+**/idea-sandbox

+ 78 - 0
环境配置/技术规范/p3c/idea-plugin/README.md

@@ -0,0 +1,78 @@
+# Idea Plugin 
+---
+## <font color="green">Prepare</font>
+- Project JDK: 1.7+
+- Gradle: 3.0+(Require JDK1.8+ for gradle)
+
+## <font color="green">Build</font>
+```
+cd p3c-idea
+gradle clean buildPlugin
+```
+
+## <font color="green">Run plugin</font>
+
+```
+cd p3c-idea
+gradle runIde
+# run specific IDEA
+gradle runIde -Pidea_version=14.1.7
+```
+
+## <font color="green">Use p3c-common as your plugin dependency</font>
+```groovy
+compile 'com.alibaba.p3c.idea:p3c-common:1.0.0'
+```
+## [中文使用手册](README_cn.md)
+## <font color="green">Install</font>
+### Install from repositories
+1. <font color="blue">Settings >> Plugins >> Browse repositories... </font>
+
+    ![Switch language](doc/images/install_1.png) 
+
+2. <font color="blue"> Search plugin by keyword 'alibaba' then install 'Alibaba Java Coding Guidelines' plugin </font>
+
+    ![Switch language](doc/images/install_2.png) 
+
+3.  <font color="blue">Restart to take effect. </font>
+### Install from local zip file.
+1. Open https://plugins.jetbrains.com/plugin/10046-alibaba-java-coding-guidelines and download the latest version zip file.
+    ![download](https://gw.alicdn.com/tfscom/TB1WcF3hzlxYKJjSZFuXXaYlVXa.png)
+2. Settings >> Plugins >> Install plugin from disk...,select the downloaded zip file in previous step then restart your idea
+    ![](https://gw.alicdn.com/tfscom/TB1WFsKiqigSKJjSsppXXabnpXa.png)
+
+## <font color="green">Use</font>
+
+1. <font color="blue">Switch language</font>
+
+	![Switch language](doc/images/switch_language.png) 
+
+2. <font color="blue">Inspections</font>  
+
+	![Real time](doc/images/inspection.png) 
+	
+	![Settings](doc/images/inspection_setting.png)  
+
+3. <font color="blue">Code Analyze</font>  
+
+	![Settings](doc/images/analyze.png)  
+	
+	<font color="blue">We use the idea standard Inspection Results to show our violations.</font>  
+	 
+	![Result](doc/images/inspection_result.png)  
+	
+	<font color="blue">We can also analyze file which is modified before vcs checkin.</font>  
+	
+	![Before Checkin](doc/images/analyze_before_checkin.png) 
+
+## <font color="green">Other</font>
+1. <font color="blue">[中文乱码解决方法](https://github.com/alibaba/p3c/issues/32#issuecomment-336762512)</font>
+
+	* <font color="blue">Appearance&Behavior -> Appearance -> UI Options -> Name 里面设置成微软雅黑(microsoft yahei light)</font>
+
+	   ![Font](doc/images/change_name.png) 
+ 
+	* <font color="blue">Switch Language to English and restart.</font>
+
+	   ![Switch language](doc/images/normal_view.png) 
+

+ 119 - 0
环境配置/技术规范/p3c/idea-plugin/README_cn.md

@@ -0,0 +1,119 @@
+> 首先非常感谢大家对插件的支持与意见,英文版的文档还是略为简单,这里详细介绍一下插件的安装使用。
+
+## 插件安装
+### 通过Jetbrains官方仓库安装
+1. 打开 Settings >> Plugins >> Browse repositories...
+
+ ![](https://gw.alicdn.com/tfscom/TB1Qn83ifBNTKJjy1zdXXaScpXa.png)
+ 
+2. 在搜索框输入alibaba即可看到Alibaba Java Code Guidelines插件,点击Install进行安装,然后重启IDE生效 `注意:因为插件zip包托管在Jetbrains官方CDN上,所以是从国外的服务器进行下载,可能会出现超时的情况`
+
+   ![](https://gw.alicdn.com/tfscom/TB1vcGbmYsTMeJjy1zcXXXAgXXa.png)
+
+### 通过下载安装包进行安装
+1. 打开[插件](https://plugins.jetbrains.com/plugin/10046-alibaba-java-coding-guidelines)页面
+
+![download](https://gw.alicdn.com/tfscom/TB1WcF3hzlxYKJjSZFuXXaYlVXa.png)
+
+2. Settings >> Plugins >> Install plugin from disk...,选择刚刚下载的zip包安装,然后重启IDE
+
+ ![](https://gw.alicdn.com/tfscom/TB1WFsKiqigSKJjSsppXXabnpXa.png)
+
+
+### 注意
+
+最低支持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>)
+
+插件基于JDK1.7打包,所以IDEA启动时使用的JDK版本如果是1.6的话就会报Unsupported major.minor version 51.0异常,建议大家都升级一下。
+
+### [中文乱码解决方法](https://github.com/alibaba/p3c/issues/32#issuecomment-336762512)
+
+1. 修改字体——Appearance&Behavior -> Appearance -> UI Options -> Name 里面设置成中文字体——如微软雅黑(microsoft yahei light)、文泉驿(linux)
+
+	![](https://gw.alicdn.com/tfscom/TB14wTmm3oQMeJjy0FoXXcShVXa.png) 
+
+2. Switch Language to English and restart.
+
+	![](https://gw.alicdn.com/tfscom/TB1Z6u1mYsTMeJjSszhXXcGCFXa.png) 
+	   
+
+## 插件使用
+
+目前插件实现了开发手册中的的53条规则,大部分基于PMD实现,其中有4条规则基于IDEA实现,并且基于IDEA <a href="https://www.jetbrains.com/help/idea/code-inspection.html" target="_blank">Inspection</a>实现了实时检测功能。部分规则实现了Quick Fix功能,对于可以提供Quick Fix但没有提供的,我们会尽快实现,也欢迎有兴趣的同学加入进来一起努力。
+目前插件检测有两种模式:实时检测、手动触发。
+
+### 实时检测
+实时检测功能会在开发过程中对当前文件进行检测,并以高亮的形式提示出来,同时也可以支持Quick Fix,该功能默认开启,可以通过配置关闭。 
+
+#### 结果高亮提示
+
+<p style="text-indent:2em">检测结果高亮提示,并且鼠标放上去会弹出提示信息。</p>
+
+  ![](https://gw.alicdn.com/tfscom/TB17wt3mYsTMeJjSszdXXcEupXa.png)
+
+  ![](https://gw.alicdn.com/tfscom/TB1Rq85ifNNTKJjSspkXXaeWFXa.png)
+
+#### <a href="https://www.jetbrains.com/help/idea/intention-actions.html" target="_blank">Intention</a> QuickFix功能
+
+Alt+Enter键可呼出Intention菜单,不同的规则会提示不同信息的Quick Fix按钮
+
+  ![](https://gw.alicdn.com/tfscom/TB1twLMsOAKL1JjSZFoXXagCFXa.png)
+
+#### 关闭实时检测  
+在某些情况下,我们不希望对代码提示违规信息,比如我们在阅读Github开源项目代码的时候,如果界面出现一堆红色、黄色的提示,此时心里肯定是飘过一万只草泥马。这个时候我们可以通过Inspection的设置关闭实时检测功能。
+1. 通过右键快速关闭(打开)所有规则的实时检测功能
+
+  ![](https://gw.alicdn.com/tfscom/TB1dBbDe_1z01JjSZFCXXXY.XXa.png)
+2. 通过Settings >> Editor >> Inspections 进行手动设置  
+
+ ![](https://gw.alicdn.com/tfscom/TB1zhCBsiFTMKJjSZFAXXckJpXa.png)
+
+也可以关闭某条规则的实时检测功能或者修改提示级别。
+   
+### 代码扫描
+
+可以通过右键菜单、Toolbar按钮、快捷键三种方式手动触发代码检测。同时结果面板中可以对部分实现了QuickFix功能的规则进行快速修复。 
+
+#### 触发扫描
+在当前编辑的文件中点击右键,可以在弹出的菜单中触发对该文件的检测。
+
+   ![](https://gw.alicdn.com/tfscom/TB1Wj49mYsTMeJjSszdXXcEupXa.png)
+   
+在左侧的Project目录树种点击右键,可以触发对整个工程或者选择的某个目录、文件进行检测。
+
+   ![](https://gw.alicdn.com/tfscom/TB1h_XciWmgSKJjSspiXXXyJFXa.png)
+   
+   如果您打开了IDE的Toolbar,也可以通过Toolbar中的按钮来触发检测,目前Toolbar的按钮触发的检测范围与您IDE当时的焦点有关,如当前编辑的文件或者是Project目录树选中的项,是不是感觉与右键菜单的检测范围类似呢。
+
+   ![](https://gw.alicdn.com/tfscom/TB1q3Nfi6uhSKJjSspmXXcQDpXa.png)
+   使用快捷键(Ctrl+Shift+Alt+J)触发弹出窗口,选择检测范围;您也可自定义快捷键。
+
+   ![](https://gw.alicdn.com/tfscom/TB1k4uXmYwTMeJjSszfXXXbtFXa.png) 
+   
+   ![](https://gw.alicdn.com/tfscom/TB1ObqXifxNTKJjy0FjXXX6yVXa.png)
+   
+#### 扫描结果  
+检测结果直接使用IDEA Run Inspection By Name功能的结果界面,插件的检测结果分级为Blocker、Critical、Major。默认按等级分组,方便统计每个级别错误的数量。
+
+![](https://gw.alicdn.com/tfscom/TB1aC1yifJNTKJjSspoXXc6mpXa.png)
+
+   
+默认情况我们在结果面板需要双击具体违规项才能打开对应的源文件,开启Autoscroll To Source选项,单击面板中的文件名、或者是具体的违规项的时候IDEA会自动打开对应的源文件。
+
+   ![](https://gw.alicdn.com/tfscom/TB1aIixmYsTMeJjy1zcXXXAgXXa.png)
+ 
+#### QuickFix
+对于实现Quick Fix的规则,在结果面板中可以直接一键修复 `注意:IDEA14、15可以通过左下角的灯泡进行一键修复操作。`
+
+   ![](https://gw.alicdn.com/tfscom/TB1Kw5Vm3oQMeJjy0FpXXcTxpXa.png)
+   
+   ![](https://gw.alicdn.com/tfscom/TB1lHZZiGagSKJjy0FbXXa.mVXa.png)
+   
+#### 其他
+面板中其他按钮的功能大家自行探索吧,就不一一赘述了
+
+### 代码提交时检测
+1. 在提交代码框勾选Alibaba Code Guidelines选项
+   ![](https://gw.alicdn.com/tfscom/TB1u_ZZjamgSKJjSspiXXXyJFXa.png)
+2. 如果有违反手册的地方会提示是否继续提交,选择取消后会自动对修改的代码进行扫描
+   ![](https://gw.alicdn.com/tfscom/TB1r5PUXbb85uJjSZFmXXcgsFXa.png)

+ 38 - 0
环境配置/技术规范/p3c/idea-plugin/build.gradle

@@ -0,0 +1,38 @@
+buildscript {
+    repositories {
+        maven {
+            url "https://oss.sonatype.org/content/repositories/snapshots/"
+        }
+        maven {
+            url 'http://dl.bintray.com/jetbrains/intellij-plugin-service'
+        }
+        mavenCentral()
+
+    }
+    dependencies {
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+allprojects {
+    group 'com.alibaba.p3c.idea'
+    apply plugin: 'java'
+    apply plugin: 'kotlin'
+    apply plugin: 'maven-publish'
+
+    sourceCompatibility = 1.8
+    compileJava.options.encoding = 'UTF-8'
+    configurations.all {
+        resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
+    }
+    repositories {
+        jcenter()
+        mavenCentral()
+    }
+
+    dependencies {
+        compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+        testCompile group: 'junit', name: 'junit', version: '4.11'
+    }
+}
+

BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/analyze.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/analyze_before_checkin.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/change_name.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/inspection.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/inspection_result.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/inspection_setting.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/install_1.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/install_2.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/normal_view.png


BIN
环境配置/技术规范/p3c/idea-plugin/doc/images/switch_language.png


+ 8 - 0
环境配置/技术规范/p3c/idea-plugin/gradle.properties

@@ -0,0 +1,8 @@
+kotlin_version=1.3.50
+#idea_version=171.3780.15
+idea_version=145.258.11
+plugin_name=Alibaba Java Coding Guidelines
+gradle_jetbrains_version=0.4.5
+systemProp.file.encoding=UTF-8
+
+plugin_version=2.0.2

BIN
环境配置/技术规范/p3c/idea-plugin/gradle/wrapper/gradle-wrapper.jar


+ 6 - 0
环境配置/技术规范/p3c/idea-plugin/gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
+#Wed Nov 30 15:31:46 CST 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip

+ 172 - 0
环境配置/技术规范/p3c/idea-plugin/gradlew

@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save ( ) {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"

+ 84 - 0
环境配置/技术规范/p3c/idea-plugin/gradlew.bat

@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 107 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/build.gradle

@@ -0,0 +1,107 @@
+plugins {
+    id "org.jetbrains.intellij" version '0.4.5'
+}
+apply plugin: 'kotlin'
+apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'signing'
+
+javadoc {
+    options.tags = ["date"]
+}
+
+task javadocJar(type: Jar, dependsOn: javadoc) {
+    classifier = 'javadoc'
+    from 'build/docs/javadoc'
+}
+
+task sourcesJar(type: Jar) {
+    classifier = 'sources'
+    from sourceSets.main.allSource
+}
+
+artifacts {
+    archives jar
+    archives javadocJar
+    archives sourcesJar
+}
+
+def myPlugins = []
+def versionDotIndex = idea_version.indexOf('.')
+def intVersion = versionDotIndex == -1 ? Integer.parseInt(idea_version) : Integer.parseInt(idea_version.substring(0, versionDotIndex))
+if (intVersion >= 2019 || (intVersion < 1000 && intVersion >= 193)) {
+    myPlugins = ['java']
+}
+
+intellij {
+    version idea_version
+    plugins = myPlugins
+    pluginName plugin_name
+    updateSinceUntilBuild false
+    sandboxDirectory "$project.buildDir/idea-sandbox/$idea_version"
+}
+version '2.0.1'
+
+ext.isReleaseVersion = !version.endsWith("SNAPSHOT")
+
+dependencies {
+    compile group: 'org.freemarker', name: 'freemarker', version: '2.3.25-incubating'
+    compile 'com.alibaba.p3c:p3c-pmd:2.0.1'
+    compile group: 'org.javassist', name: 'javassist', version: '3.21.0-GA'
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
+
+            repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
+                authentication(userName: findProperty('ossrhUsername'), password: findProperty('ossrhPassword'))
+            }
+
+            snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
+                authentication(userName: findProperty('ossrhUsername'), password: findProperty('ossrhPassword'))
+            }
+
+            pom.project {
+                name 'p3c-common'
+                packaging 'jar'
+                description 'P3c Idea Plugin Common.'
+                url 'https://github.com/alibaba/p3c'
+
+                scm {
+                    url 'https://github.com/alibaba/p3c'
+                    connection 'scm:git:https://git@github.com/alibaba/p3c.git'
+                }
+
+                licenses {
+                    license {
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                        distribution 'repo'
+                    }
+                }
+
+                developers {
+                    developer {
+                        id 'junlie'
+                        name 'Junlie'
+                        email 'sean.caikang@gmail.com'
+                    }
+                    developer {
+                        id 'ZengHou'
+                        name 'ZengHou'
+                        email 'fengwei1983@gmail.com'
+                    }
+                }
+            }
+        }
+    }
+}
+
+signing {
+    required {
+        isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives")
+    }
+    sign configurations.archives
+}

+ 38 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/java/icons/P3cIcons.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package icons;
+
+import javax.swing.Icon;
+
+import com.intellij.openapi.util.IconLoader;
+
+/**
+ * @author caikang
+ * @date 2016/12/28
+ */
+public final class P3cIcons {
+    private P3cIcons() {
+        throw new AssertionError("icons.P3cIcons"
+            + " instances for you!");
+    }
+
+    public static final Icon ANALYSIS_ACTION = IconLoader.getIcon("/icons/ali-ide-run.png");
+
+    public static final Icon PROJECT_INSPECTION_ON = IconLoader.getIcon("/icons/qiyong.png");
+    public static final Icon PROJECT_INSPECTION_OFF = IconLoader.getIcon("/icons/tingyong.png");
+    public static final Icon LANGUAGE = IconLoader.getIcon("/icons/language.png");
+    public static final Icon ALIBABA = IconLoader.getIcon("/icons/alibaba.png");
+}

+ 209 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/AliInspectionAction.kt

@@ -0,0 +1,209 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.p3c.idea.action
+
+import com.alibaba.p3c.idea.compatible.inspection.InspectionProfileService
+import com.alibaba.p3c.idea.compatible.inspection.Inspections
+import com.alibaba.p3c.idea.i18n.P3cBundle
+import com.alibaba.p3c.idea.inspection.AliBaseInspection
+import com.alibaba.p3c.idea.util.NumberConstants
+import com.google.common.collect.Lists
+import com.intellij.analysis.AnalysisScope
+import com.intellij.analysis.AnalysisUIOptions
+import com.intellij.analysis.BaseAnalysisActionDialog
+import com.intellij.codeInspection.InspectionManager
+import com.intellij.codeInspection.InspectionsBundle
+import com.intellij.codeInspection.ex.GlobalInspectionContextImpl
+import com.intellij.codeInspection.ex.InspectionManagerEx
+import com.intellij.codeInspection.ex.InspectionToolWrapper
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.components.ServiceManager
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.module.ModuleUtilCore
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vfs.VfsUtilCore
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.wm.ToolWindowId
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.PsiFileSystemItem
+import com.intellij.psi.PsiManager
+import java.awt.event.KeyEvent
+
+/**
+ * @author caikang
+ * @date 2016/12/11
+ */
+class AliInspectionAction : AnAction() {
+
+    override fun actionPerformed(e: AnActionEvent) {
+        val project = e.project ?: return
+        val analysisUIOptions = ServiceManager.getService(project, AnalysisUIOptions::class.java)!!
+        analysisUIOptions.GROUP_BY_SEVERITY = true
+
+        val managerEx = InspectionManager.getInstance(project) as InspectionManagerEx
+        val toolWrappers = Inspections.aliInspections(project) {
+            it.tool is AliBaseInspection
+        }
+        val psiElement = e.getData<PsiElement>(CommonDataKeys.PSI_ELEMENT)
+        val psiFile = e.getData<PsiFile>(CommonDataKeys.PSI_FILE)
+        val virtualFile = e.getData<VirtualFile>(CommonDataKeys.VIRTUAL_FILE)
+        val virtualFiles = e.getData<Array<VirtualFile>>(CommonDataKeys.VIRTUAL_FILE_ARRAY)
+        var analysisScope: AnalysisScope? = null
+        var projectDir = false
+        if (psiFile != null) {
+            analysisScope = AnalysisScope(psiFile)
+            projectDir = isBaseDir(psiFile.virtualFile, project)
+        } else if (virtualFiles != null && virtualFiles.size > NumberConstants.INTEGER_SIZE_OR_LENGTH_0) {
+            analysisScope = AnalysisScope(project, Lists.newArrayList<VirtualFile>(*virtualFiles))
+            projectDir = virtualFiles.any {
+                isBaseDir(it, project)
+            }
+        } else {
+            if (virtualFile != null && virtualFile.isDirectory) {
+                val psiDirectory = PsiManager.getInstance(project).findDirectory(virtualFile)
+                if (psiDirectory != null) {
+                    analysisScope = AnalysisScope(psiDirectory)
+                    projectDir = isBaseDir(virtualFile, project)
+                }
+            }
+            if (analysisScope == null && virtualFile != null) {
+                analysisScope = AnalysisScope(project, listOf(virtualFile))
+                projectDir = isBaseDir(virtualFile, project)
+            }
+            if (analysisScope == null) {
+                projectDir = true
+                analysisScope = AnalysisScope(project)
+            }
+        }
+        if (e.inputEvent is KeyEvent) {
+            inspectForKeyEvent(project, managerEx, toolWrappers, psiElement, psiFile, virtualFile, analysisScope)
+            return
+        }
+        val element = psiFile ?: psiElement
+        analysisScope.isIncludeTestSource = false
+        analysisScope.setSearchInLibraries(true)
+        createContext(
+            toolWrappers, managerEx, element,
+            projectDir, analysisScope
+        ).doInspections(analysisScope)
+    }
+
+    private fun isBaseDir(file: VirtualFile, project: Project): Boolean {
+        if (file.canonicalPath == null || project.basePath == null) {
+            return false
+        }
+        return project.basePath == file.canonicalPath
+    }
+
+    private fun inspectForKeyEvent(
+        project: Project, managerEx: InspectionManagerEx,
+        toolWrappers: List<InspectionToolWrapper<*, *>>, psiElement: PsiElement?, psiFile: PsiFile?,
+        virtualFile: VirtualFile?, analysisScope: AnalysisScope
+    ) {
+        var module: Module? = null
+        if (virtualFile != null && project.baseDir != virtualFile) {
+            module = ModuleUtilCore.findModuleForFile(virtualFile, project)
+        }
+
+        val uiOptions = AnalysisUIOptions.getInstance(project)
+        uiOptions.ANALYZE_TEST_SOURCES = false
+        val dialog = BaseAnalysisActionDialog(
+            "Select Analyze Scope", "Analyze Scope", project, analysisScope,
+            module?.name, true, uiOptions, psiElement
+        )
+
+        if (!dialog.showAndGet()) {
+            return
+        }
+        val scope = dialog.getScope(uiOptions, analysisScope, project, module)
+        scope.setSearchInLibraries(true)
+        val element = psiFile ?: psiElement
+        createContext(
+            toolWrappers, managerEx, element,
+            dialog.isProjectScopeSelected, scope
+        ).doInspections(scope)
+    }
+
+    override fun update(e: AnActionEvent) {
+        e.presentation.text = P3cBundle.getMessage("com.alibaba.p3c.idea.action.AliInspectionAction.text")
+    }
+
+    companion object {
+        private val logger = Logger.getInstance(AliInspectionAction::class.java)
+
+        private fun getTitle(element: PsiElement?, isProjectScopeSelected: Boolean): String? {
+            if (element == null) {
+                return null
+            }
+            if (isProjectScopeSelected) {
+                return "Project"
+            }
+            if (element is PsiFileSystemItem) {
+                return VfsUtilCore.getRelativePath(element.virtualFile, element.project.baseDir)
+            }
+            return null
+        }
+
+        fun createContext(
+            toolWrapperList: List<InspectionToolWrapper<*, *>>,
+            managerEx: InspectionManagerEx, psiElement: PsiElement?,
+            projectScopeSelected: Boolean, scope: AnalysisScope
+        ):
+            GlobalInspectionContextImpl {
+            // remove last same scope content
+            val project = managerEx.project
+            val title = getTitle(psiElement, projectScopeSelected)
+            val model = InspectionProfileService.createSimpleProfile(toolWrapperList, managerEx, psiElement)
+            title?.let {
+                model.name = it
+            }
+
+            val inspectionContext = createNewGlobalContext(
+                managerEx, projectScopeSelected
+            )
+            InspectionProfileService.setExternalProfile(model, inspectionContext)
+
+            val toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.INSPECTION)
+
+            if (toolWindow != null) {
+                val contentManager = toolWindow.contentManager
+                val contentTitle = title?.let {
+                    InspectionsBundle.message("inspection.results.for.profile.toolwindow.title", it, scope.shortenName)
+                }
+                val content = contentManager.contents.firstOrNull {
+                    contentTitle != null && (it.tabName == contentTitle || it.tabName.endsWith(contentTitle))
+                }
+                content?.let {
+                    contentManager.removeContent(content, true)
+                }
+            }
+
+            return inspectionContext
+        }
+
+        private fun createNewGlobalContext(
+            managerEx: InspectionManagerEx,
+            projectScopeSelected: Boolean
+        ): GlobalInspectionContextImpl {
+            return PmdGlobalInspectionContextImpl(managerEx.project, managerEx.contentManager, projectScopeSelected)
+        }
+    }
+}

+ 273 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/PmdGlobalInspectionContextImpl.kt

@@ -0,0 +1,273 @@
+package com.alibaba.p3c.idea.action
+
+import com.alibaba.p3c.idea.component.AliProjectComponent
+import com.alibaba.p3c.idea.ep.InspectionActionExtensionPoint
+import com.alibaba.p3c.idea.inspection.AliLocalInspectionToolProvider
+import com.alibaba.p3c.idea.inspection.PmdRuleInspectionIdentify
+import com.alibaba.p3c.idea.pmd.AliPmdProcessor
+import com.intellij.analysis.AnalysisScope
+import com.intellij.codeInsight.daemon.impl.DaemonProgressIndicator
+import com.intellij.codeInspection.ex.GlobalInspectionContextImpl
+import com.intellij.codeInspection.ui.InspectionResultsView
+import com.intellij.concurrency.JobLauncher
+import com.intellij.concurrency.JobLauncherImpl
+import com.intellij.concurrency.SensitiveProgressWrapper
+import com.intellij.diagnostic.ThreadDumper
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.ex.ApplicationManagerEx
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.openapi.progress.ProcessCanceledException
+import com.intellij.openapi.progress.ProgressIndicator
+import com.intellij.openapi.progress.ProgressIndicatorProvider
+import com.intellij.openapi.progress.ProgressManager
+import com.intellij.openapi.progress.util.ProgressIndicatorUtils
+import com.intellij.openapi.project.DumbService
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.project.ProjectUtilCore
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.util.EmptyRunnable
+import com.intellij.openapi.util.NotNullLazyValue
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.psi.PsiFile
+import com.intellij.psi.search.LocalSearchScope
+import com.intellij.psi.search.SearchScope
+import com.intellij.psi.util.PsiUtilCore
+import com.intellij.ui.content.ContentManager
+import com.intellij.util.ExceptionUtil
+import com.intellij.util.IncorrectOperationException
+import com.intellij.util.Processor
+import com.intellij.util.ReflectionUtil
+import com.intellij.util.containers.ContainerUtil
+import gnu.trove.THashSet
+import net.sourceforge.pmd.RuleViolation
+import java.util.Queue
+import java.util.concurrent.ArrayBlockingQueue
+import java.util.concurrent.BlockingQueue
+import java.util.concurrent.Future
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit.SECONDS
+
+/**
+ * @date 2020/06/19
+ * @author caikang
+ */
+class PmdGlobalInspectionContextImpl(
+    project: Project,
+    contentManager: NotNullLazyValue<ContentManager>,
+    private val projectScopeSelected: Boolean
+) :
+    GlobalInspectionContextImpl(project, contentManager) {
+
+    private val logger = Logger.getInstance(PmdGlobalInspectionContextImpl::class.java)
+
+    override fun runTools(scope: AnalysisScope, runGlobalToolsOnly: Boolean, isOfflineInspections: Boolean) {
+        val usedTools = usedTools
+        val hasPmdTools = usedTools.any {
+            it.tool.tool is PmdRuleInspectionIdentify
+        }
+        if (hasPmdTools) {
+            val progressIndicator =
+                ProgressIndicatorProvider.getGlobalProgressIndicator()
+                    ?: throw IncorrectOperationException("Must be run under progress")
+            pmdNodeWarmUp(scope, progressIndicator, isOfflineInspections)
+        }
+        super.runTools(scope, runGlobalToolsOnly, isOfflineInspections)
+        if (myProgressIndicator.isCanceled) {
+            return
+        }
+        InspectionActionExtensionPoint.extension.extensions.forEach {
+            try {
+                it.doOnInspectionFinished(this, projectScopeSelected)
+            } catch (e: Exception) {
+                logger.warn(e)
+            }
+        }
+    }
+
+    private fun pmdNodeWarmUp(
+        scope: AnalysisScope,
+        progressIndicator: ProgressIndicator,
+        isOfflineInspections: Boolean
+    ) {
+        val aliProjectComponent = project.getComponent(AliProjectComponent::class.java)
+        // run pmd inspection
+        val processor = Processor { file: PsiFile ->
+            ProgressManager.checkCanceled()
+            val readActionSuccess =
+                DumbService.getInstance(project).tryRunReadActionInSmartMode(
+                    {
+                        if (!file.isValid) {
+                            return@tryRunReadActionInSmartMode true
+                        }
+                        val virtualFile = file.virtualFile
+                        if (!scope.contains(virtualFile)) {
+                            logger.info(file.name + "; scope: " + scope + "; " + virtualFile)
+                            return@tryRunReadActionInSmartMode true
+                        }
+                        val path = virtualFile.canonicalPath?.toLowerCase() ?: ""
+                        if (!path.endsWith(".java") && !path.endsWith(".vm")) {
+                            return@tryRunReadActionInSmartMode true
+                        }
+                        doPmdProcess(file, aliProjectComponent, virtualFile)
+                        true
+                    }, "Inspect code is not available until indices are ready"
+                )
+            if (readActionSuccess == null || !readActionSuccess) {
+                throw ProcessCanceledException()
+            }
+            true
+        }
+        val headlessEnvironment = ApplicationManager.getApplication().isHeadlessEnvironment
+        val searchScope =
+            ApplicationManager.getApplication().runReadAction<SearchScope, RuntimeException> { scope.toSearchScope() }
+        val localScopeFiles: MutableSet<VirtualFile>? = if (searchScope is LocalSearchScope) THashSet() else null
+        val filesToInspect: BlockingQueue<PsiFile> = ArrayBlockingQueue(1000)
+        val iteratingIndicator: ProgressIndicator = SensitiveProgressWrapper(progressIndicator)
+        val startIterateScopeInBackground = ReflectionUtil.getDeclaredMethod(
+            javaClass.superclass,
+            "startIterateScopeInBackground",
+            AnalysisScope::class.java,
+            Collection::class.java,
+            headlessEnvironment.javaClass,
+            BlockingQueue::class.java,
+            ProgressIndicator::class.java
+        )
+        requireNotNull(startIterateScopeInBackground) {
+            "method GlobalInspectionContextImpl.startIterateScopeInBackground not found in this IDEA version"
+        }
+        val future: Future<*> = startIterateScopeInBackground.invoke(
+            this,
+            scope,
+            localScopeFiles,
+            headlessEnvironment,
+            filesToInspect,
+            iteratingIndicator
+        ) as Future<*>
+        val dependentIndicators =
+            ReflectionUtil.getField(javaClass, this, List::class.java, "dependentIndicators")?.map {
+                it as ProgressIndicator
+            }?.toMutableList()
+        try {
+            val filesFailedToInspect: Queue<PsiFile> = LinkedBlockingQueue()
+            while (true) {
+                val disposable = Disposer.newDisposable()
+                val wrapper: ProgressIndicator = DaemonProgressIndicator()
+                dependentIndicators?.let {
+                    it.add(wrapper)
+                }
+                try {
+                    // avoid "attach listener"/"write action" race
+                    ApplicationManager.getApplication().runReadAction {
+                        wrapper.start()
+                        ProgressIndicatorUtils.forceWriteActionPriority(wrapper, disposable)
+                        // there is a chance we are racing with write action, in which case just registered listener might not be called, retry.
+                        if (ApplicationManagerEx.getApplicationEx().isWriteActionPending) {
+                            throw ProcessCanceledException()
+                        }
+                    }
+                    // use wrapper here to cancel early when write action start but do not affect the original indicator
+                    (JobLauncher.getInstance() as JobLauncherImpl).processQueue(
+                        filesToInspect,
+                        filesFailedToInspect,
+                        wrapper,
+                        PsiUtilCore.NULL_PSI_FILE,
+                        processor
+                    )
+                    break
+                } catch (e: ProcessCanceledException) {
+                    progressIndicator.checkCanceled()
+                    assert(
+                        isOfflineInspections || !ApplicationManager.getApplication().isReadAccessAllowed
+                    ) {
+                        """
+                                    Must be outside read action. PCE=
+                                    ${ExceptionUtil.getThrowableText(e)}
+                                    """.trimIndent()
+                    }
+                    assert(
+                        isOfflineInspections || !ApplicationManager.getApplication().isDispatchThread
+                    ) {
+                        """
+                                    Must be outside EDT. PCE=
+                                    ${ExceptionUtil.getThrowableText(e)}
+                                    """.trimIndent()
+                    }
+
+                    // wait for write action to complete
+                    ApplicationManager.getApplication().runReadAction(EmptyRunnable.getInstance())
+                } finally {
+                    dependentIndicators?.let {
+                        it.remove(wrapper)
+                    }
+                    Disposer.dispose(disposable)
+                }
+            }
+        } finally {
+            iteratingIndicator.cancel() // tell file scanning thread to stop
+            filesToInspect.clear() // let file scanning thread a chance to put TOMBSTONE and complete
+            try {
+                future[30, SECONDS]
+            } catch (e: java.lang.Exception) {
+                logger.error(
+                    """
+                                Thread dump: 
+                                ${ThreadDumper.dumpThreadsToString()}
+                                """.trimIndent(), e
+                )
+            }
+        }
+        ProgressManager.checkCanceled()
+    }
+
+    private fun doPmdProcess(
+        file: PsiFile,
+        aliProjectComponent: AliProjectComponent,
+        virtualFile: VirtualFile
+    ) {
+        val url: String = ProjectUtilCore.displayUrlRelativeToProject(
+            virtualFile,
+            virtualFile.presentableUrl,
+            project,
+            true,
+            false
+        )
+        myProgressIndicator.text = "PMD Process in $url"
+        val violations =
+            AliPmdProcessor(AliLocalInspectionToolProvider.getRuleSets()).processFile(
+                file,
+                false
+            )
+        val fileContext = aliProjectComponent.getFileContext(virtualFile)
+        fileContext?.let { fc ->
+            val ruleViolations = ContainerUtil.createConcurrentSoftValueMap<String, List<RuleViolation>>()
+            for (entry in violations.groupBy {
+                it.rule.name
+            }) {
+                ruleViolations[entry.key] = entry.value
+            }
+            fc.ruleViolations = ruleViolations
+        }
+    }
+
+    override fun close(noSuspiciousCodeFound: Boolean) {
+        super.close(noSuspiciousCodeFound)
+        InspectionActionExtensionPoint.extension.extensions.forEach {
+            try {
+                it.doOnClose(noSuspiciousCodeFound, project)
+            } catch (e: Exception) {
+                logger.warn(e)
+            }
+        }
+    }
+
+    override fun addView(view: InspectionResultsView) {
+        super.addView(view)
+        InspectionActionExtensionPoint.extension.extensions.forEach {
+            try {
+                it.doOnView(view)
+            } catch (e: Exception) {
+                logger.warn(e)
+            }
+        }
+    }
+}

+ 51 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/SwitchLanguageAction.kt

@@ -0,0 +1,51 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.p3c.idea.action
+
+import com.alibaba.p3c.idea.config.P3cConfig
+import com.alibaba.p3c.idea.i18n.P3cBundle
+import com.alibaba.smartfox.idea.common.util.BalloonNotifications
+import com.alibaba.smartfox.idea.common.util.getService
+import com.intellij.notification.NotificationListener
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.application.ex.ApplicationManagerEx
+import com.intellij.openapi.project.DumbAware
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/20
+ */
+class SwitchLanguageAction : AnAction(), DumbAware {
+    private val p3cConfig = P3cConfig::class.java.getService()
+
+    private val textKey = "com.alibaba.p3c.action.switch_language.text"
+
+    override fun actionPerformed(e: AnActionEvent) {
+        p3cConfig.toggleLanguage()
+        BalloonNotifications.showSuccessNotification(P3cBundle.getMessage("$textKey.success"), e.project,
+                NotificationListener { notification, _ ->
+                    notification.expire()
+                    ApplicationManagerEx.getApplicationEx().restart(false)
+                }, sticky = true)
+    }
+
+    override fun update(e: AnActionEvent) {
+        e.presentation.text = P3cBundle.getMessage("$textKey.cur_${p3cConfig.locale}")
+    }
+}

+ 59 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/ToggleProjectInspectionAction.kt

@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.p3c.idea.action
+
+import com.alibaba.p3c.idea.compatible.inspection.InspectionProfileService
+import com.alibaba.p3c.idea.compatible.inspection.Inspections
+import com.alibaba.p3c.idea.config.SmartFoxProjectConfig
+import com.alibaba.p3c.idea.i18n.P3cBundle
+import com.alibaba.p3c.idea.inspection.AliBaseInspection
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.components.ServiceManager
+import icons.P3cIcons
+
+/**
+ *
+ * Open or close inspections
+ * @author caikang
+ * @date 2017/03/14
+4
+ */
+class ToggleProjectInspectionAction : AnAction() {
+    val textKey = "com.alibaba.p3c.idea.action.ToggleProjectInspectionAction.text"
+
+    override fun actionPerformed(e: AnActionEvent) {
+        val project = e.project ?: return
+        val smartFoxConfig = ServiceManager.getService(project, SmartFoxProjectConfig::class.java)
+        val tools = Inspections.aliInspections(project) {
+            it.tool is AliBaseInspection
+        }
+        InspectionProfileService.toggleInspection(project, tools, smartFoxConfig.projectInspectionClosed)
+        smartFoxConfig.projectInspectionClosed = !smartFoxConfig.projectInspectionClosed
+    }
+
+    override fun update(e: AnActionEvent) {
+        val project = e.project ?: return
+        val smartFoxConfig = ServiceManager.getService(project, SmartFoxProjectConfig::class.java)
+        e.presentation.text = if (smartFoxConfig.projectInspectionClosed) {
+            e.presentation.icon = P3cIcons.PROJECT_INSPECTION_ON
+            P3cBundle.getMessage("$textKey.open")
+        } else {
+            e.presentation.icon = P3cIcons.PROJECT_INSPECTION_OFF
+            P3cBundle.getMessage("$textKey.close")
+        }
+    }
+}

+ 116 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/compatible/inspection/InspectionProfileService.kt

@@ -0,0 +1,116 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.p3c.idea.compatible.inspection
+
+import com.alibaba.smartfox.idea.common.util.PluginVersions
+import com.google.common.collect.Sets
+import com.intellij.codeInspection.ex.GlobalInspectionContextImpl
+import com.intellij.codeInspection.ex.InspectionManagerEx
+import com.intellij.codeInspection.ex.InspectionProfileImpl
+import com.intellij.codeInspection.ex.InspectionToolWrapper
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.InvalidDataException
+import com.intellij.openapi.util.WriteExternalException
+import com.intellij.profile.codeInspection.InspectionProjectProfileManager
+import com.intellij.psi.PsiElement
+import org.jdom.Element
+import java.util.LinkedHashSet
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/03/01
+ */
+object InspectionProfileService {
+    fun createSimpleProfile(toolWrapperList: List<InspectionToolWrapper<*, *>>,
+            managerEx: InspectionManagerEx, psiElement: PsiElement?): InspectionProfileImpl {
+        val profile = getProjectInspectionProfile(managerEx.project)
+        val allWrappers: LinkedHashSet<InspectionToolWrapper<*, *>> = Sets.newLinkedHashSet()
+        allWrappers.addAll(toolWrapperList)
+        val forCompile = allWrappers
+        for (toolWrapper in allWrappers) {
+            profile.collectDependentInspections(toolWrapper, forCompile, managerEx.project)
+        }
+        val model = when (PluginVersions.baseVersion) {
+            in PluginVersions.baseVersion171..Int.MAX_VALUE -> {
+                val clz = Class.forName("com.intellij.codeInspection.ex.InspectionProfileKt")
+                val method = clz.methods.first { it.name == "createSimple" }
+                method.invoke(null, "Alibaba Coding Guidelines", managerEx.project, allWrappers.toList())
+                        as InspectionProfileImpl
+            }
+            PluginVersions.baseVersion163 -> {
+                val method = profile.javaClass.methods.first {
+                    it.name == "createSimple"
+                }
+                method.invoke(null, "Alibaba Coding Guidelines", managerEx.project, allWrappers.toList())
+                        as InspectionProfileImpl
+            }
+            else -> {
+                val method = profile.javaClass.methods.first {
+                    it.name == "createSimple"
+                }
+                method.invoke(null, "Alibaba Coding Guidelines", managerEx.project, allWrappers.toTypedArray())
+                        as InspectionProfileImpl
+            }
+        }
+        try {
+            val element = Element("toCopy")
+            for (wrapper in allWrappers) {
+                wrapper.tool.writeSettings(element)
+                val tw = if (psiElement == null) {
+                    model.getInspectionTool(wrapper.shortName, managerEx.project)
+                } else {
+                    model.getInspectionTool(wrapper.shortName, psiElement)
+                }
+                tw!!.tool.readSettings(element)
+            }
+        } catch (ignored: WriteExternalException) {
+        } catch (ignored: InvalidDataException) {
+        }
+        return model
+    }
+
+    fun toggleInspection(project: Project, aliInspections: List<InspectionToolWrapper<*, *>>, closed: Boolean) {
+        val profile = getProjectInspectionProfile(project)
+        val shortNames = aliInspections.map {
+            it.tool.shortName
+        }
+        profile.removeScopes(shortNames, "AlibabaCodeAnalysis", project)
+        val method = profile.javaClass.methods.first {
+            it.name == if (closed) {
+                "enableToolsByDefault"
+            } else {
+                "disableToolByDefault"
+            }
+        }
+        method.invoke(profile, shortNames, project)
+        profile.profileChanged()
+        profile.scopesChanged()
+    }
+
+    fun setExternalProfile(profile: InspectionProfileImpl,
+            inspectionContext: GlobalInspectionContextImpl) {
+        val method = inspectionContext.javaClass.methods.first {
+            it.name == "setExternalProfile" && it.parameterTypes.size == 1 && it.parameterTypes.first().isAssignableFrom(InspectionProfileImpl::class.java)
+        }
+        method.invoke(inspectionContext, profile)
+    }
+
+    fun getProjectInspectionProfile(project: Project): InspectionProfileImpl {
+        return InspectionProjectProfileManager.getInstance(project).inspectionProfile as InspectionProfileImpl
+    }
+}

+ 67 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/compatible/inspection/Inspections.kt

@@ -0,0 +1,67 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.p3c.idea.compatible.inspection
+
+import com.google.common.base.Splitter
+import com.intellij.codeInspection.ex.InspectionProfileImpl
+import com.intellij.codeInspection.ex.InspectionToolWrapper
+import com.intellij.codeInspection.ex.ScopeToolState
+import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection
+import com.intellij.openapi.project.Project
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/03/01
+ */
+object Inspections {
+    fun aliInspections(project: Project, filter: (InspectionToolWrapper<*, *>) -> Boolean): List<InspectionToolWrapper<*, *>> {
+        val profile = InspectionProfileService.getProjectInspectionProfile(project)
+        return getAllTools(project, profile).filter(filter)
+    }
+
+    fun addCustomTag(project: Project, tag: String) {
+        val profile = InspectionProfileService.getProjectInspectionProfile(project)
+        val javaDocLocalInspection = profile.getInspectionTool("JavaDoc", project)?.tool
+                as? JavaDocLocalInspection ?: return
+        if (javaDocLocalInspection.myAdditionalJavadocTags.isEmpty()) {
+            javaDocLocalInspection.myAdditionalJavadocTags = tag
+            return
+        }
+
+        val tags = Splitter.on(',').splitToList(javaDocLocalInspection.myAdditionalJavadocTags)
+        if (tags.contains(tag)) {
+            return
+        }
+        javaDocLocalInspection.myAdditionalJavadocTags += "," + tag
+        profile.profileChanged()
+        profile.scopesChanged()
+    }
+
+    private fun getAllTools(project: Project, profile: InspectionProfileImpl): List<InspectionToolWrapper<*, *>> {
+        val method = InspectionProfileImpl::class.java.methods.first {
+            it.name == "getAllTools"
+        }
+
+        val result = if (method.parameterTypes.isNotEmpty()) {
+            method.invoke(profile, project)
+        } else {
+            method.invoke(profile)
+        }
+        return (result as List<ScopeToolState>).map { it.tool }
+    }
+}

+ 150 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/component/AliProjectComponent.kt

@@ -0,0 +1,150 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.p3c.idea.component
+
+import com.alibaba.p3c.idea.compatible.inspection.Inspections
+import com.alibaba.p3c.idea.config.P3cConfig
+import com.alibaba.p3c.idea.i18n.P3cBundle
+import com.alibaba.p3c.idea.inspection.AliPmdInspectionInvoker
+import com.alibaba.p3c.idea.pmd.SourceCodeProcessor
+import com.alibaba.p3c.idea.util.withLockNotInline
+import com.alibaba.p3c.pmd.I18nResources
+import com.alibaba.smartfox.idea.common.component.AliBaseProjectComponent
+import com.intellij.openapi.actionSystem.ActionManager
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.vfs.VirtualFileAdapter
+import com.intellij.openapi.vfs.VirtualFileEvent
+import com.intellij.openapi.vfs.VirtualFileListener
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.openapi.vfs.VirtualFileMoveEvent
+import com.intellij.psi.PsiManager
+import net.sourceforge.pmd.RuleViolation
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.locks.ReentrantReadWriteLock
+
+/**
+ * @author caikang
+ * @date 2016/12/13
+ */
+class AliProjectComponent(
+    private val project: Project,
+    val p3cConfig: P3cConfig
+) : AliBaseProjectComponent {
+    private val listener: VirtualFileListener
+    private val javaExtension = ".java"
+    private val velocityExtension = ".vm"
+
+    private val lock = ReentrantReadWriteLock()
+    private val readLock = lock.readLock()
+    private val writeLock = lock.writeLock()
+
+    private val fileContexts = ConcurrentHashMap<String, FileContext>()
+
+    init {
+        listener = object : VirtualFileAdapter() {
+            override fun contentsChanged(event: VirtualFileEvent) {
+                val path = getFilePath(event) ?: return
+                PsiManager.getInstance(project).findFile(event.file) ?: return
+                if (!p3cConfig.ruleCacheEnable) {
+                    AliPmdInspectionInvoker.refreshFileViolationsCache(event.file)
+                }
+                if (!p3cConfig.astCacheEnable) {
+                    SourceCodeProcessor.invalidateCache(path)
+                }
+                SourceCodeProcessor.invalidUserTrigger(path)
+                fileContexts[path]?.ruleViolations = null
+            }
+
+            override fun fileDeleted(event: VirtualFileEvent) {
+                val path = getFilePath(event)
+                path?.let {
+                    SourceCodeProcessor.invalidateCache(it)
+                    removeFileContext(it)
+                }
+                super.fileDeleted(event)
+            }
+
+            override fun fileMoved(event: VirtualFileMoveEvent) {
+                val path = getFilePath(event)
+                path?.let {
+                    SourceCodeProcessor.invalidateCache(it)
+                    removeFileContext(it)
+                }
+                super.fileMoved(event)
+            }
+
+            private fun getFilePath(event: VirtualFileEvent): String? {
+                val path = event.file.canonicalPath
+                if (path == null || !(path.endsWith(javaExtension) || path.endsWith(velocityExtension))) {
+                    return null
+                }
+                return path
+            }
+        }
+    }
+
+    override fun initComponent() {
+        I18nResources.changeLanguage(p3cConfig.locale)
+        val analyticsGroup = ActionManager.getInstance().getAction(analyticsGroupId)
+        analyticsGroup.templatePresentation.text = P3cBundle.getMessage(analyticsGroupText)
+    }
+
+    override fun projectOpened() {
+        Inspections.addCustomTag(project, "date")
+        VirtualFileManager.getInstance().addVirtualFileListener(listener)
+    }
+
+    override fun projectClosed() {
+        VirtualFileManager.getInstance().removeVirtualFileListener(listener)
+    }
+
+    companion object {
+        val analyticsGroupId = "com.alibaba.p3c.analytics.action_group"
+        val analyticsGroupText = "$analyticsGroupId.text"
+    }
+
+    data class FileContext(
+        val lock: ReentrantReadWriteLock,
+        var ruleViolations: Map<String, List<RuleViolation>>? = null
+    )
+
+    fun removeFileContext(path: String) {
+        fileContexts.remove(path)
+    }
+
+    fun getFileContext(virtualFile: VirtualFile?): FileContext? {
+        val file = virtualFile?.canonicalPath ?: return null
+        val result = readLock.withLockNotInline {
+            fileContexts[file]
+        }
+        if (result != null) {
+            return result
+        }
+        return writeLock.withLockNotInline {
+            val finalContext = fileContexts[file]
+            if (finalContext != null) {
+                return@withLockNotInline finalContext
+            }
+            val lock = ReentrantReadWriteLock()
+            FileContext(
+                lock = lock
+            ).also {
+                fileContexts[file] = it
+            }
+        }
+    }
+}

+ 35 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/component/CommonSettingsApplicationComponent.kt

@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.p3c.idea.component
+
+import com.alibaba.p3c.idea.util.HighlightInfoTypes
+import com.alibaba.p3c.idea.util.HighlightSeverities
+import com.alibaba.smartfox.idea.common.component.AliBaseApplicationComponent
+import com.intellij.codeInsight.daemon.impl.SeverityRegistrar
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/19
+ */
+class CommonSettingsApplicationComponent : AliBaseApplicationComponent {
+    override fun initComponent() {
+        SeverityRegistrar.registerStandard(HighlightInfoTypes.BLOCKER, HighlightSeverities.BLOCKER)
+        SeverityRegistrar.registerStandard(HighlightInfoTypes.CRITICAL, HighlightSeverities.CRITICAL)
+        SeverityRegistrar.registerStandard(HighlightInfoTypes.MAJOR, HighlightSeverities.MAJOR)
+    }
+}

+ 68 - 0
环境配置/技术规范/p3c/idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/config/P3cConfig.kt

@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999-2017 Alibaba Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.p3c.idea.config
+
+import com.intellij.openapi.components.PersistentStateComponent
+import com.intellij.openapi.components.State
+import com.intellij.openapi.components.Storage
+import com.intellij.util.xmlb.XmlSerializerUtil
+import java.util.Locale
+
+/**
+ *
+ *
+ * @author caikang
+ * @date 2017/06/19
+ */
+@State(name = "P3cConfig", storages = [Storage(file = "smartfox/p3c.xml")])
+class P3cConfig : PersistentStateComponent<P3cConfig> {
+    var astCacheTime = 1000L
+    var astCacheEnable = true
+
+    var ruleCacheTime = 1000L
+    var ruleCacheEnable = false
+
+    var analysisBeforeCheckin = false
+
+    var locale: String = ""
+        get() {
+            if (field.isEmpty()) {
+                val lang = Locale.getDefault().language
+                return if (lang != Locale.ENGLISH.language && lang != Locale.CHINESE.language) {
+                    Locale.ENGLISH.language
+                } else Locale.getDefault().language
+            }
+
+            return field
+        }
+
+    fun toggleLanguage() {
+        locale = if (localeEn == locale) localeZh else localeEn
+    }
+
+    override fun getState(): P3cConfig {
+        return this
+    }
+
+    override fun loadState(state: P3cConfig) {
+        XmlSerializerUtil.copyBean(state, this)
+    }
+
+    companion object {
+        val localeEn = Locale.ENGLISH.language!!
+        val localeZh = Locale.CHINESE.language!!
+    }
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов