Repository: alibaba/p3c
Branch: master
Commit: 6c59c8c36ecd
Files: 329
Total size: 1.1 MB
Directory structure:
gitextract_c6djlc1m/
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── ------.md
│ ├── bug_report.md
│ ├── feature_request.md
│ └── rule-issue-template.md
├── .gitignore
├── README.md
├── eclipse-plugin/
│ ├── .gitignore
│ ├── README.md
│ ├── README_cn.md
│ ├── com.alibaba.smartfox.eclipse.feature/
│ │ ├── build.properties
│ │ ├── feature.properties
│ │ ├── feature.xml
│ │ └── pom.xml
│ ├── com.alibaba.smartfox.eclipse.plugin/
│ │ ├── META-INF/
│ │ │ └── MANIFEST.MF
│ │ ├── build.properties
│ │ ├── plugin.xml
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── kotlin/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ └── smartfox/
│ │ │ └── eclipse/
│ │ │ ├── QuickFix.kt
│ │ │ ├── SmartfoxActivator.kt
│ │ │ ├── handler/
│ │ │ │ ├── CodeAnalysisHandler.kt
│ │ │ │ └── SwitchLanguageHandler.kt
│ │ │ ├── job/
│ │ │ │ ├── CodeAnalysis.kt
│ │ │ │ └── P3cMutex.kt
│ │ │ ├── message/
│ │ │ │ └── P3cBundle.kt
│ │ │ ├── pmd/
│ │ │ │ ├── RulePriority.kt
│ │ │ │ └── rule/
│ │ │ │ ├── AbstractEclipseRule.kt
│ │ │ │ ├── AvoidAccessStaticViaInstanceRule.kt
│ │ │ │ ├── AvoidUseDeprecationRule.kt
│ │ │ │ ├── MapOrSetKeyShouldOverrideHashCodeEqualsRule.kt
│ │ │ │ └── MissingOverrideAnnotationRule.kt
│ │ │ ├── ui/
│ │ │ │ ├── AllRulesPreferencePage.kt
│ │ │ │ ├── AllRulesView.kt
│ │ │ │ ├── InspectionResultTreeContentProvider.kt
│ │ │ │ ├── InspectionResultTreeLabelProvider.kt
│ │ │ │ ├── InspectionResultView.kt
│ │ │ │ ├── InspectionResults.kt
│ │ │ │ ├── QuickFixAction.kt
│ │ │ │ ├── RuleDetailComposite.kt
│ │ │ │ ├── RuleDetailView.kt
│ │ │ │ ├── Violations.kt
│ │ │ │ └── pmd/
│ │ │ │ ├── BasicLineStyleListener.kt
│ │ │ │ ├── ContentBuilder.kt
│ │ │ │ ├── FontBuilder.kt
│ │ │ │ ├── StringArranger.kt
│ │ │ │ ├── StyleExtractor.kt
│ │ │ │ ├── SyntaxData.kt
│ │ │ │ └── SyntaxManager.kt
│ │ │ └── util/
│ │ │ ├── CleanUps.kt
│ │ │ └── MarkerUtil.kt
│ │ └── resources/
│ │ ├── messages/
│ │ │ ├── P3cBundle.xml
│ │ │ └── P3cBundle_en.xml
│ │ ├── rulesets/
│ │ │ └── java/
│ │ │ ├── ali-pmd.xml
│ │ │ └── ali-ruleOnEclipse.xml
│ │ └── syntax/
│ │ └── java.properties
│ ├── com.alibaba.smartfox.eclipse.updatesite/
│ │ ├── category.xml
│ │ └── pom.xml
│ └── pom.xml
├── idea-plugin/
│ ├── .gitignore
│ ├── README.md
│ ├── README_cn.md
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── p3c-common/
│ │ ├── build.gradle
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── icons/
│ │ │ └── P3cIcons.java
│ │ ├── kotlin/
│ │ │ └── com/
│ │ │ └── alibaba/
│ │ │ ├── p3c/
│ │ │ │ └── idea/
│ │ │ │ ├── action/
│ │ │ │ │ ├── AliInspectionAction.kt
│ │ │ │ │ ├── PmdGlobalInspectionContextImpl.kt
│ │ │ │ │ ├── SwitchLanguageAction.kt
│ │ │ │ │ └── ToggleProjectInspectionAction.kt
│ │ │ │ ├── compatible/
│ │ │ │ │ └── inspection/
│ │ │ │ │ ├── InspectionProfileService.kt
│ │ │ │ │ └── Inspections.kt
│ │ │ │ ├── component/
│ │ │ │ │ ├── AliProjectComponent.kt
│ │ │ │ │ └── CommonSettingsApplicationComponent.kt
│ │ │ │ ├── config/
│ │ │ │ │ ├── P3cConfig.kt
│ │ │ │ │ └── SmartFoxProjectConfig.kt
│ │ │ │ ├── ep/
│ │ │ │ │ ├── InspectionActionExtensionPoint.kt
│ │ │ │ │ └── package-info.java
│ │ │ │ ├── i18n/
│ │ │ │ │ └── P3cBundle.kt
│ │ │ │ ├── inspection/
│ │ │ │ │ ├── AliAccessToNonThreadSafeStaticFieldFromInstanceInspection.kt
│ │ │ │ │ ├── AliArrayNamingShouldHaveBracketInspection.kt
│ │ │ │ │ ├── AliBaseInspection.kt
│ │ │ │ │ ├── AliControlFlowStatementWithoutBracesInspection.kt
│ │ │ │ │ ├── AliEqualsAvoidNullInspection.kt
│ │ │ │ │ ├── AliLocalInspectionToolProvider.kt
│ │ │ │ │ ├── AliLongLiteralsEndingWithLowercaseLInspection.kt
│ │ │ │ │ ├── AliPmdInspection.kt
│ │ │ │ │ ├── AliPmdInspectionInvoker.kt
│ │ │ │ │ ├── AliWrapperTypeEqualityInspection.kt
│ │ │ │ │ ├── DelegateLocalInspectionTool.kt
│ │ │ │ │ ├── DelegatePmdInspection.kt
│ │ │ │ │ ├── PmdRuleInspectionIdentify.kt
│ │ │ │ │ ├── RuleInspectionUtils.kt
│ │ │ │ │ └── standalone/
│ │ │ │ │ ├── AliAccessStaticViaInstanceInspection.kt
│ │ │ │ │ ├── AliDeprecationInspection.kt
│ │ │ │ │ ├── AliMissingOverrideAnnotationInspection.kt
│ │ │ │ │ └── MapOrSetKeyShouldOverrideHashCodeEqualsInspection.kt
│ │ │ │ ├── pmd/
│ │ │ │ │ ├── AliPmdProcessor.kt
│ │ │ │ │ ├── SourceCodeProcessor.kt
│ │ │ │ │ └── index/
│ │ │ │ │ ├── InspectionDataSource.kt
│ │ │ │ │ └── InspectionRenderer.kt
│ │ │ │ ├── quickfix/
│ │ │ │ │ ├── AliQuickFix.kt
│ │ │ │ │ ├── AvoidStartWithDollarAndUnderLineNamingQuickFix.kt
│ │ │ │ │ ├── ClassMustHaveAuthorQuickFix.kt
│ │ │ │ │ ├── ConstantFieldShouldBeUpperCaseQuickFix.kt
│ │ │ │ │ ├── DecorateInspectionFix.kt
│ │ │ │ │ ├── LowerCamelCaseVariableNamingQuickFix.kt
│ │ │ │ │ └── VmQuietReferenceQuickFix.kt
│ │ │ │ ├── util/
│ │ │ │ │ ├── DocumentUtils.kt
│ │ │ │ │ ├── HighlightDisplayLevels.kt
│ │ │ │ │ ├── HighlightInfoTypes.kt
│ │ │ │ │ ├── HighlightSeverities.kt
│ │ │ │ │ ├── NumberConstants.kt
│ │ │ │ │ ├── ObjectConstants.kt
│ │ │ │ │ ├── ProblemsUtils.kt
│ │ │ │ │ ├── QuickFixes.kt
│ │ │ │ │ └── withLockNotInline.kt
│ │ │ │ └── vcs/
│ │ │ │ ├── AliCodeAnalysisCheckinHandler.kt
│ │ │ │ └── AliCodeAnalysisCheckinHandlerFactory.kt
│ │ │ └── smartfox/
│ │ │ └── idea/
│ │ │ └── common/
│ │ │ ├── component/
│ │ │ │ ├── AliBaseApplicationComponent.kt
│ │ │ │ └── AliBaseProjectComponent.kt
│ │ │ └── util/
│ │ │ ├── BalloonNotifications.kt
│ │ │ ├── CommonExtensions.kt
│ │ │ └── PluginVersions.kt
│ │ └── resources/
│ │ ├── messages/
│ │ │ ├── P3cBundle.xml
│ │ │ └── P3cBundle_en.xml
│ │ ├── rulesets/
│ │ │ └── java/
│ │ │ └── ali-pmd.xml
│ │ └── tpl/
│ │ └── StaticDescriptionTemplate.ftl
│ ├── p3c-idea/
│ │ ├── build.gradle
│ │ └── src/
│ │ └── main/
│ │ └── resources/
│ │ └── META-INF/
│ │ ├── p3c.xml
│ │ └── plugin.xml
│ └── settings.gradle
├── license.txt
├── p3c-formatter/
│ ├── eclipse-codestyle.xml
│ └── eclipse-codetemplate.xml
├── p3c-gitbook/
│ ├── .gitignore
│ ├── MySQL数据库/
│ │ ├── ORM映射.md
│ │ ├── SQL语句.md
│ │ ├── 建表规约.md
│ │ └── 索引规约.md
│ ├── README.md
│ ├── SUMMARY.md
│ ├── book.json
│ ├── styles/
│ │ └── website.css
│ ├── 单元测试.md
│ ├── 安全规约.md
│ ├── 工程结构/
│ │ ├── 二方库依赖.md
│ │ ├── 应用分层.md
│ │ └── 服务器.md
│ ├── 异常日志/
│ │ ├── 其他.md
│ │ ├── 异常处理.md
│ │ └── 日志规约.md
│ ├── 本手册专有名词.md
│ ├── 版本历史.md
│ └── 编程规约/
│ ├── OOP规范.md
│ ├── 代码格式.md
│ ├── 命名风格.md
│ ├── 常量定义.md
│ ├── 并发处理.md
│ ├── 控制语句.md
│ ├── 注释规约.md
│ └── 集合处理.md
└── p3c-pmd/
├── .gitignore
├── README.md
├── pom.xml
└── src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── alibaba/
│ │ └── p3c/
│ │ └── pmd/
│ │ ├── I18nResources.java
│ │ ├── fix/
│ │ │ └── FixClassTypeResolver.java
│ │ └── lang/
│ │ ├── AbstractXpathRule.java
│ │ ├── java/
│ │ │ ├── rule/
│ │ │ │ ├── AbstractAliRule.java
│ │ │ │ ├── AbstractPojoRule.java
│ │ │ │ ├── comment/
│ │ │ │ │ ├── AbstractAliCommentRule.java
│ │ │ │ │ ├── AbstractMethodOrInterfaceMethodMustUseJavadocRule.java
│ │ │ │ │ ├── AvoidCommentBehindStatementRule.java
│ │ │ │ │ ├── ClassMustHaveAuthorRule.java
│ │ │ │ │ ├── CommentsMustBeJavadocFormatRule.java
│ │ │ │ │ ├── EnumConstantsMustHaveCommentRule.java
│ │ │ │ │ └── RemoveCommentedCodeRule.java
│ │ │ │ ├── concurrent/
│ │ │ │ │ ├── AvoidCallStaticSimpleDateFormatRule.java
│ │ │ │ │ ├── AvoidConcurrentCompetitionRandomRule.java
│ │ │ │ │ ├── AvoidManuallyCreateThreadRule.java
│ │ │ │ │ ├── AvoidUseTimerRule.java
│ │ │ │ │ ├── CountDownShouldInFinallyRule.java
│ │ │ │ │ ├── ThreadLocalShouldRemoveRule.java
│ │ │ │ │ ├── ThreadPoolCreationRule.java
│ │ │ │ │ └── ThreadShouldSetNameRule.java
│ │ │ │ ├── constant/
│ │ │ │ │ ├── UndefineMagicConstantRule.java
│ │ │ │ │ └── UpperEllRule.java
│ │ │ │ ├── exception/
│ │ │ │ │ ├── AvoidReturnInFinallyRule.java
│ │ │ │ │ ├── MethodReturnWrapperTypeRule.java
│ │ │ │ │ └── TransactionMustHaveRollbackRule.java
│ │ │ │ ├── flowcontrol/
│ │ │ │ │ ├── AvoidComplexConditionRule.java
│ │ │ │ │ ├── AvoidNegationOperatorRule.java
│ │ │ │ │ ├── NeedBraceRule.java
│ │ │ │ │ └── SwitchStatementRule.java
│ │ │ │ ├── naming/
│ │ │ │ │ ├── AbstractClassShouldStartWithAbstractNamingRule.java
│ │ │ │ │ ├── ArrayNamingShouldHaveBracketRule.java
│ │ │ │ │ ├── AvoidStartWithDollarAndUnderLineNamingRule.java
│ │ │ │ │ ├── BooleanPropertyShouldNotStartWithIsRule.java
│ │ │ │ │ ├── ClassNamingShouldBeCamelRule.java
│ │ │ │ │ ├── ConstantFieldShouldBeUpperCaseRule.java
│ │ │ │ │ ├── ExceptionClassShouldEndWithExceptionRule.java
│ │ │ │ │ ├── LowerCamelCaseVariableNamingRule.java
│ │ │ │ │ ├── PackageNamingRule.java
│ │ │ │ │ ├── ServiceOrDaoClassShouldEndWithImplRule.java
│ │ │ │ │ └── TestClassShouldEndWithTestNamingRule.java
│ │ │ │ ├── oop/
│ │ │ │ │ ├── BigDecimalAvoidDoubleConstructorRule.java
│ │ │ │ │ ├── EqualsAvoidNullRule.java
│ │ │ │ │ ├── PojoMustOverrideToStringRule.java
│ │ │ │ │ ├── PojoMustUsePrimitiveFieldRule.java
│ │ │ │ │ ├── PojoNoDefaultValueRule.java
│ │ │ │ │ ├── StringConcatRule.java
│ │ │ │ │ └── WrapperTypeEqualityRule.java
│ │ │ │ ├── orm/
│ │ │ │ │ └── IbatisMethodQueryForListRule.java
│ │ │ │ ├── other/
│ │ │ │ │ ├── AvoidApacheBeanUtilsCopyRule.java
│ │ │ │ │ ├── AvoidDoubleOrFloatEqualCompareRule.java
│ │ │ │ │ ├── AvoidMissUseOfMathRandomRule.java
│ │ │ │ │ ├── AvoidNewDateGetTimeRule.java
│ │ │ │ │ ├── AvoidPatternCompileInMethodRule.java
│ │ │ │ │ ├── MethodTooLongRule.java
│ │ │ │ │ └── UseRightCaseForDateFormatRule.java
│ │ │ │ ├── set/
│ │ │ │ │ ├── ClassCastExceptionWithSubListToArrayListRule.java
│ │ │ │ │ ├── ClassCastExceptionWithToArrayRule.java
│ │ │ │ │ ├── CollectionInitShouldAssignCapacityRule.java
│ │ │ │ │ ├── ConcurrentExceptionWithModifyOriginSubListRule.java
│ │ │ │ │ ├── DontModifyInForeachCircleRule.java
│ │ │ │ │ └── UnsupportedExceptionWithModifyAsListRule.java
│ │ │ │ └── util/
│ │ │ │ ├── NodeSortUtils.java
│ │ │ │ └── NodeUtils.java
│ │ │ └── util/
│ │ │ ├── GeneratedCodeUtils.java
│ │ │ ├── NumberConstants.java
│ │ │ ├── PojoUtils.java
│ │ │ ├── SpiLoader.java
│ │ │ ├── StringAndCharConstants.java
│ │ │ ├── VariableUtils.java
│ │ │ ├── ViolationUtils.java
│ │ │ └── namelist/
│ │ │ ├── NameListConfig.java
│ │ │ ├── NameListService.java
│ │ │ └── NameListServiceImpl.java
│ │ └── vm/
│ │ └── rule/
│ │ └── other/
│ │ └── UseQuietReferenceNotationRule.java
│ ├── kotlin/
│ │ └── com/
│ │ └── alibaba/
│ │ └── p3c/
│ │ └── pmd/
│ │ └── lang/
│ │ └── java/
│ │ └── rule/
│ │ └── concurrent/
│ │ └── LockShouldWithTryFinallyRule.kt
│ └── resources/
│ ├── META-INF/
│ │ └── services/
│ │ └── com.alibaba.p3c.pmd.lang.java.util.namelist.NameListService
│ ├── messages.xml
│ ├── messages_en.xml
│ ├── namelist.properties
│ └── rulesets/
│ ├── java/
│ │ ├── ali-comment.xml
│ │ ├── ali-concurrent.xml
│ │ ├── ali-constant.xml
│ │ ├── ali-exception.xml
│ │ ├── ali-flowcontrol.xml
│ │ ├── ali-naming.xml
│ │ ├── ali-oop.xml
│ │ ├── ali-orm.xml
│ │ ├── ali-other.xml
│ │ └── ali-set.xml
│ └── vm/
│ └── ali-other.xml
└── test/
├── java/
│ └── com/
│ └── alibaba/
│ └── p3c/
│ └── pmd/
│ ├── lang/
│ │ ├── java/
│ │ │ └── rule/
│ │ │ ├── comment/
│ │ │ │ └── CommentRulesTest.java
│ │ │ ├── concurrent/
│ │ │ │ └── ConcurrentRuleTest.java
│ │ │ ├── constant/
│ │ │ │ └── ConstantRulesTest.java
│ │ │ ├── exception/
│ │ │ │ └── ExceptionRulesTest.java
│ │ │ ├── flowcontrol/
│ │ │ │ └── FlowControlRuleTest.java
│ │ │ ├── naming/
│ │ │ │ └── NamingRulesTest.java
│ │ │ ├── oop/
│ │ │ │ └── OopRuleTest.java
│ │ │ ├── orm/
│ │ │ │ └── OrmRulesTest.java
│ │ │ ├── other/
│ │ │ │ ├── OtherRulesTest.java
│ │ │ │ └── UseRightCaseForDateFormatRuleTest.java
│ │ │ └── set/
│ │ │ └── SetRulesTest.java
│ │ └── vm/
│ │ └── rule/
│ │ └── other/
│ │ └── OtherRulesTest.java
│ └── testframework/
│ ├── ExtendRuleTst.java
│ └── ExtendSimpleAggregatorTst.java
└── resources/
└── com/
└── alibaba/
└── p3c/
└── pmd/
└── lang/
├── java/
│ └── rule/
│ ├── comment/
│ │ └── xml/
│ │ ├── AbstractMethodOrInterfaceMethodMustUseJavadocRule.xml
│ │ ├── AvoidCommentBehindStatementRule.xml
│ │ ├── ClassMustHaveAuthorRule.xml
│ │ ├── CommentsMustBeJavadocFormatRule.xml
│ │ ├── EnumConstantsMustHaveCommentRule.xml
│ │ └── RemoveCommentedCodeRule.xml
│ ├── concurrent/
│ │ └── xml/
│ │ ├── AvoidCallStaticSimpleDateFormatRule.xml
│ │ ├── AvoidConcurrentCompetitionRandomRule.xml
│ │ ├── AvoidManuallyCreateThreadRule.xml
│ │ ├── AvoidUseTimerRule.xml
│ │ ├── CountDownShouldInFinallyRule.xml
│ │ ├── LockShouldWithTryFinallyRule.xml
│ │ ├── ThreadLocalShouldRemoveRule.xml
│ │ ├── ThreadPoolCreationRule.xml
│ │ └── ThreadShouldSetNameRule.xml
│ ├── constant/
│ │ └── xml/
│ │ ├── UndefineMagicConstantRule.xml
│ │ └── UpperEllRule.xml
│ ├── exception/
│ │ └── xml/
│ │ ├── AvoidReturnInFinallyRule.xml
│ │ ├── MethodReturnWrapperTypeRule.xml
│ │ └── TransactionMustHaveRollbackRule.xml
│ ├── flowcontrol/
│ │ └── xml/
│ │ ├── AvoidComplexConditionRule.xml
│ │ ├── AvoidNegationOperatorRule.xml
│ │ ├── NeedBraceRule.xml
│ │ └── SwitchStatementRule.xml
│ ├── naming/
│ │ └── xml/
│ │ ├── AbstractClassShouldStartWithAbstractNamingRule.xml
│ │ ├── ArrayNamingShouldHaveBracketRule.xml
│ │ ├── AvoidStartWithDollarAndUnderLineNamingRule.xml
│ │ ├── BooleanPropertyShouldNotStartWithIsRule.xml
│ │ ├── ClassNamingShouldBeCamelRule.xml
│ │ ├── ConstantFieldShouldBeUpperCaseRule.xml
│ │ ├── ExceptionClassShouldEndWithExceptionRule.xml
│ │ ├── LowerCamelCaseVariableNamingRule.xml
│ │ ├── PackageNamingRule.xml
│ │ ├── ServiceOrDaoClassShouldEndWithImplRule.xml
│ │ └── TestClassShouldEndWithTestNamingRule.xml
│ ├── oop/
│ │ └── xml/
│ │ ├── BigDecimalAvoidDoubleConstructorRule.xml
│ │ ├── EqualsAvoidNullRule.xml
│ │ ├── PojoMustOverrideToStringRule.xml
│ │ ├── PojoMustUsePrimitiveFieldRule.xml
│ │ ├── PojoNoDefaultValueRule.xml
│ │ ├── StringConcatRule.xml
│ │ └── WrapperTypeEqualityRule.xml
│ ├── orm/
│ │ └── xml/
│ │ └── IbatisMethodQueryForListRule.xml
│ ├── other/
│ │ ├── java/
│ │ │ └── UseRightCaseForDateFormatRuleExam.java
│ │ └── xml/
│ │ ├── AvoidApacheBeanUtilsCopyRule.xml
│ │ ├── AvoidDoubleOrFloatEqualCompareRule.xml
│ │ ├── AvoidMissUseOfMathRandomRule.xml
│ │ ├── AvoidNewDateGetTimeRule.xml
│ │ ├── AvoidPatternCompileInMethodRule.xml
│ │ ├── MethodTooLongRule.xml
│ │ └── UseRightCaseForDateFormatRule.xml
│ └── set/
│ └── xml/
│ ├── ClassCastExceptionWithSubListToArrayListRule.xml
│ ├── ClassCastExceptionWithToArrayRule.xml
│ ├── CollectionInitShouldAssignCapacityRule.xml
│ ├── ConcurrentExceptionWithModifyOriginSubListRule.xml
│ ├── DontModifyInForeachCircleRule.xml
│ └── UnsupportedExceptionWithModifyAsListRule.xml
└── vm/
└── rule/
└── other/
└── xml/
└── UseQuietReferenceNotationRule.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/------.md
================================================
---
name: 规约问题模板
about: 规约问题请使用该模板
title: ''
labels: ''
assignees: ''
---
## 规约原文
## 问题描述
## 修改建议
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/rule-issue-template.md
================================================
---
name: Rule issue template
about: Rule issue please use this template.
title: ''
labels: ''
assignees: ''
---
## Rule content
## Problem description
## Advice
================================================
FILE: .gitignore
================================================
# 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
================================================
FILE: README.md
================================================
# P3C
最新版本:黄山版(2022.2.3发布)
[](https://www.apache.org/licenses/LICENSE-2.0.html)
## Preface
> We are pleased to present Alibaba Java Coding Guidelines which consolidates the best programming practices over the years from Alibaba Group's technical teams. A vast number of Java programming teams impose demanding requirements on code quality across projects as we encourage reuse and better understanding of each other's programs. We have seen many programming problems in the past. For example, defective database table structures and index designs may cause software architecture flaws and performance risks. Another example is confusing code structures being difficult to maintain. Furthermore, vulnerable code without authentication is prone to hackers’ attacks. To address these kinds of problems, we developed this document for Java developers at Alibaba.
For more information please refer the *Alibaba Java Coding Guidelines*:
- 中文版: 直接下载上方的PDF文件(黄山版)
- English Version: *[Alibaba Java Coding Guidelines](https://alibaba.github.io/Alibaba-Java-Coding-Guidelines)*
## Introduction
The project consists of 3 parts:
- [PMD implementations](p3c-pmd)
- [IntelliJ IDEA plugin](idea-plugin)
- [Eclipse plugin](eclipse-plugin)
## Rules
Forty-nine rules are realized based on PMD, please refer the P3C-PMD documentation for more detailed information. Four rules are implemented within IDE plugins (IDEA and Eclipse) as follows:
- ``[Mandatory]`` Using a deprecated class or method is prohibited.
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.
- ``[Mandatory]`` An overridden method from an interface or abstract class must be marked with @Override annotation.
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.
- ``[Mandatory]`` A static field or method should be directly referred by its class name instead of its corresponding object name.
- ``[Mandatory]`` 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.
================================================
FILE: eclipse-plugin/.gitignore
================================================
# 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
================================================
FILE: eclipse-plugin/README.md
================================================
# Eclipse Plugin
---
## Prepare
- Eclipse Juno+
- maven3.+
- JDK 1.7+
## Build
```
mvn -U clean install
```
## [中文使用手册](README_cn.md)
## Install
1. Help >> Install New Software
then enter this update site URL [https://p3c.alibaba.com/plugin/eclipse/update](https://p3c.alibaba.com/plugin/eclipse/update)

2. Follow the wizard, restart Eclipse to take effect after install success.
## Use
1. Switch language

2. Code Analyze


================================================
FILE: eclipse-plugin/README_cn.md
================================================
> 首先非常感谢大家对插件的支持与意见,Eclipse的功能相对来说比较简单,希望有更多的同学加入进来一起完善。
## 插件安装
环境:JDK1.8,Eclipse4+。有同学遇到过这样的情况,安装插件重启后,发现没有对应的菜单项,从日志上也看不到相关的异常信息,最后把JDK从1.6升级到1.8解决问题。
Help -> Install New Software...

输入Update Site地址:https://p3c.alibaba.com/plugin/eclipse/update 回车,然后勾选Ali-CodeAnalysis,再一直点Next Next...按提示走下去就好。 然后就是提示重启了,安装完毕。

注意:有同学反映插件扫描会触发很多 "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功能的规则进行快速修复。
#### 触发扫描
在当前编辑的文件中点击右键,可以在弹出的菜单中触发对该文件的检测。

在左侧的Project目录树种点击右键,可以触发对整个工程或者选择的某个目录、文件进行检测。

也可以通过Toolbar中的按钮来触发检测,目前Toolbar的按钮触发的检测范围与您IDE当时的焦点有关,如当前编辑的文件或者是Project目录树选中的项,是不是感觉与右键菜单的检测范围类似呢。

#### 扫描结果
简洁的结果面板,按规则等级分类,等级->规则->文件->违规项。同时还提供一个查看规则详情的界面。
清除结果标记更方便,支持上面提到的4条规则QuickFix。

#### 查看所有规则


#### 国际化


================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.feature/build.properties
================================================
bin.includes = feature.xml,\
feature.properties,\
smartfox.png
src.includes = build.properties,\
feature.properties,\
feature.xml,\
smartfox.png
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.feature/feature.properties
================================================
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\
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.feature/feature.xml
================================================
Alibaba Java Coding Guidelines
%copyright.text
%license.text
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.feature/pom.xml
================================================
4.0.0
com.alibaba.smartfox.eclipse
smartfox-eclipse
2.0.1-SNAPSHOT
com.alibaba.smartfox.eclipse.feature
eclipse-feature
2017
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/META-INF/MANIFEST.MF
================================================
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
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/build.properties
================================================
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/
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/plugin.xml
================================================
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/pom.xml
================================================
4.0.0
com.alibaba.smartfox.eclipse
smartfox-eclipse
2.0.1-SNAPSHOT
com.alibaba.smartfox.eclipse.plugin
eclipse-plugin
2017
false
log4j
log4j
1.2.17
com.alibaba.p3c
p3c-pmd
2.0.1
org.jetbrains.kotlin
kotlin-stdlib-jdk8
com.google.guava
guava
20.0
src/main/kotlin
org.jetbrains.kotlin
kotlin-maven-plugin
${kotlin.version}
compile
compile
compile
test-compile
test-compile
test-compile
org.apache.maven.plugins
maven-dependency-plugin
3.1.1
true
false
${project.build.directory}/lib
p2.eclipse-plugin,apex
com.alibaba.smartfox.eclipse.plugin
false
get-dependencies
process-sources
copy-dependencies
org.eclipse.m2e
lifecycle-mapping
1.0.0
org.apache.maven.plugins
maven-dependency-plugin
[0,)
copy-dependencies
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/QuickFix.kt
================================================
/*
* 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 {
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."
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/SmartfoxActivator.kt
================================================
/*
* 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
@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")
}
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/handler/CodeAnalysisHandler.kt
================================================
/*
* 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?) {
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 {
val resources = mutableSetOf()
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()!!
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
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/handler/SwitchLanguageHandler.kt
================================================
/*
* 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?) {
val text = P3cBundle.getMessage("$textKey${SmartfoxActivator.instance.locale}")
element.setText(text)
element.setTooltip(text)
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/job/CodeAnalysis.kt
================================================
/*
* 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) {
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 {
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 {
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()
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/job/P3cMutex.kt
================================================
/*
* 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
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/message/P3cBundle.kt
================================================
/*
* 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)
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/RulePriority.kt
================================================
/*
* 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
}
}
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AbstractEclipseRule.kt
================================================
/*
* 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
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AvoidAccessStaticViaInstanceRule.kt
================================================
/*
* 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
}
}
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/AvoidUseDeprecationRule.kt
================================================
/*
* 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
}
}
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/MapOrSetKeyShouldOverrideHashCodeEqualsRule.kt
================================================
/*
* 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
}
}
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/pmd/rule/MissingOverrideAnnotationRule.kt
================================================
/*
* 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())
}
}
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/AllRulesPreferencePage.kt
================================================
/*
* 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
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/AllRulesView.kt
================================================
/*
* 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)
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultTreeContentProvider.kt
================================================
/*
* 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 {
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 {
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() {
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultTreeLabelProvider.kt
================================================
/*
* 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()
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResultView.kt
================================================
/*
* 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 {
val structured = treeViewer.selection as ITreeSelection
val elements = structured.iterator()
val result = HashSet()
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
}
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/InspectionResults.kt
================================================
/*
* 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>()
var contentDescription = ""
val errors: List
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): List {
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) {
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): 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"
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/QuickFixAction.kt
================================================
/*
* 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()
fun updateFileMarkers(markers: List) {
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
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/RuleDetailComposite.kt
================================================
/*
* 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()
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/RuleDetailView.kt
================================================
/*
* 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
}
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/Violations.kt
================================================
/*
* 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,
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,
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) {
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)
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/BasicLineStyleListener.kt
================================================
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()
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/ContentBuilder.kt
================================================
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()
private val codeSpans = ArrayList()
private val linksBySpan = HashMap()
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()
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): Array {
val styles = ranges.toTypedArray()
Arrays.sort(styles) { sr1, sr2 -> sr1.start - sr2.start }
return styles
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/FontBuilder.kt
================================================
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)
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/StringArranger.kt
================================================
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 {
val lines = text.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if (lines.isEmpty()) {
return emptyList()
}
val lineSet = ArrayList(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'
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/StyleExtractor.kt
================================================
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
init {
commentOffsets = LinkedList()
}
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 {
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()
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 {
val styles = ArrayList()
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)
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/SyntaxData.kt
================================================
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? = 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) {
this.keywords = keywords
}
fun setPunctuation(thePunctuationChars: String) {
punctuation = thePunctuationChars
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/ui/pmd/SyntaxManager.kt
================================================
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()
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()
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
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/util/CleanUps.kt
================================================
// =====================================================================
//
// 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()
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): 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(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()
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,
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): 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,
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()
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,
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))
}
}
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/kotlin/com/alibaba/smartfox/eclipse/util/MarkerUtil.kt
================================================
// =====================================================================
//
// 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)
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/messages/P3cBundle.xml
================================================
阿里编码规约扫描
切换语言至英文(English)
切换语言至中文
切换到English成功,是否重启
切换到中文成功,是否重启
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/messages/P3cBundle_en.xml
================================================
Alibaba Coding Guidelines Analyze
Switch language to English
Switch language to Chinese
Switch language to English success,restart?
Switch language to Chinese success,restart?
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/rulesets/java/ali-pmd.xml
================================================
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/rulesets/java/ali-ruleOnEclipse.xml
================================================
rule.standalone.MissingOverrideAnnotationRule.desc
1
1
rule.standalone.AvoidUseDeprecationRule.desc
2
rule.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsRule.desc
2
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.plugin/src/main/resources/syntax/java.properties
================================================
# 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
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.updatesite/category.xml
================================================
Alibaba Java Coding Guidelines
================================================
FILE: eclipse-plugin/com.alibaba.smartfox.eclipse.updatesite/pom.xml
================================================
4.0.0
com.alibaba.smartfox.eclipse
smartfox-eclipse
2.0.1-SNAPSHOT
com.alibaba.smartfox.eclipse.updatesite
eclipse-repository
2017
================================================
FILE: eclipse-plugin/pom.xml
================================================
4.0.0
com.alibaba.smartfox.eclipse
smartfox-eclipse
2.0.1-SNAPSHOT
pom
2017
1.0.0
${tycho.version}
http://download.eclipse.org/releases/neon
UTF-8
http://download.eclipse.org/tools/ajdt/46/dev/update
1.3.30
juno
com.alibaba.smartfox.eclipse.plugin
com.alibaba.smartfox.eclipse.feature
com.alibaba.smartfox.eclipse.updatesite
junit
junit
4.11
test
org.jetbrains.kotlin
kotlin-stdlib-jdk8
${kotlin.version}
compile
juno
p2
http://mirrors.ustc.edu.cn/eclipse/releases/juno/
sonatype-nexus-snapshots
Sonatype Nexus Snapshots
https://oss.sonatype.org/content/repositories/snapshots
false
true
org.eclipse.tycho
tycho-maven-plugin
${tycho.version}
true
org.eclipse.tycho
target-platform-configuration
linux
gtk
x86
linux
gtk
x86_64
win32
win32
x86
win32
win32
x86_64
macosx
cocoa
x86_64
org.eclipse.tycho
target-platform-configuration
${tycho.version}
org.eclipse.tycho
tycho-compiler-plugin
${tycho.version}
1.8
UTF-8
-err:-forbidden
org.codehaus.mojo
aspectj-maven-plugin
${aspectj.plugin.version}
org.aspectj
aspectjtools
${aspectj.version}
org.eclipse.tycho
tycho-packaging-plugin
${tycho.version}
org.eclipse.tycho
tycho-surefire-plugin
${tycho.version}
true
org.eclipse.tycho
tycho-source-plugin
${tycho.version}
false
org.eclipse.tycho
tycho-p2-director-plugin
${tycho.version}
org.eclipse.tycho
tycho-p2-repository-plugin
${tycho.version}
smartfox-eclipse-plugin
org.eclipse.tycho.extras
tycho-source-feature-plugin
${tycho-extras.version}
org.eclipse.tycho.extras
tycho-custom-bundle-plugin
${tycho-extras.version}
org.eclipse.tycho
tycho-p2-plugin
${tycho.version}
warn
none
http://download.eclipse.org/eclipse/updates/4.4
================================================
FILE: idea-plugin/.gitignore
================================================
# 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
================================================
FILE: idea-plugin/README.md
================================================
# Idea Plugin
---
## Prepare
- Project JDK: 1.7+
- Gradle: 3.0+(Require JDK1.8+ for gradle)
## Build
```
cd p3c-idea
../gradlew clean buildPlugin
```
## Run plugin
```
cd p3c-idea
../gradlew runIde
# run specific IDEA
../gradlew runIde -Pidea_version=2018.3
```
## Use p3c-common as your plugin dependency
```groovy
compile 'com.alibaba.p3c.idea:p3c-common:1.0.0'
```
## [中文使用手册](README_cn.md)
## Install
### Install from repositories
1. Settings >> Plugins >> Browse repositories...

2. Search plugin by keyword 'alibaba' then install 'Alibaba Java Coding Guidelines' plugin

3. Restart to take effect.
### Install from local zip file.
1. Open https://plugins.jetbrains.com/plugin/10046-alibaba-java-coding-guidelines and download the latest version zip file.

2. Settings >> Plugins >> Install plugin from disk...,select the downloaded zip file in previous step then restart your idea

## Use
1. Switch language

2. Inspections


3. Code Analyze

We use the idea standard Inspection Results to show our violations.

We can also analyze file which is modified before vcs checkin.

## Other
1. [中文乱码解决方法](https://github.com/alibaba/p3c/issues/32#issuecomment-336762512)
* Appearance&Behavior -> Appearance -> UI Options -> Name 里面设置成微软雅黑(microsoft yahei light)

* Switch Language to English and restart.

================================================
FILE: idea-plugin/README_cn.md
================================================
> 首先非常感谢大家对插件的支持与意见,英文版的文档还是略为简单,这里详细介绍一下插件的安装使用。
## 插件安装
### 通过Jetbrains官方仓库安装
1. 打开 Settings >> Plugins >> Browse repositories...

2. 在搜索框输入alibaba即可看到Alibaba Java Code Guidelines插件,点击Install进行安装,然后重启IDE生效 `注意:因为插件zip包托管在Jetbrains官方CDN上,所以是从国外的服务器进行下载,可能会出现超时的情况`

### 通过下载安装包进行安装
1. 打开[插件](https://plugins.jetbrains.com/plugin/10046-alibaba-java-coding-guidelines)页面

2. Settings >> Plugins >> Install plugin from disk...,选择刚刚下载的zip包安装,然后重启IDE

### 注意
最低支持IDEA版本为14.1(buildNumber 141.0,可以在About Intellij IDEA中查看版本信息),使用IDEA14的同学最好升级到14.1.7(历史版本传送门)
插件基于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)

2. Switch Language to English and restart.

## 插件使用
目前插件实现了开发手册中的的53条规则,大部分基于PMD实现,其中有4条规则基于IDEA实现,并且基于IDEA Inspection实现了实时检测功能。部分规则实现了Quick Fix功能,对于可以提供Quick Fix但没有提供的,我们会尽快实现,也欢迎有兴趣的同学加入进来一起努力。
目前插件检测有两种模式:实时检测、手动触发。
### 实时检测
实时检测功能会在开发过程中对当前文件进行检测,并以高亮的形式提示出来,同时也可以支持Quick Fix,该功能默认开启,可以通过配置关闭。
#### 结果高亮提示
检测结果高亮提示,并且鼠标放上去会弹出提示信息。


#### Intention QuickFix功能
Alt+Enter键可呼出Intention菜单,不同的规则会提示不同信息的Quick Fix按钮

#### 关闭实时检测
在某些情况下,我们不希望对代码提示违规信息,比如我们在阅读Github开源项目代码的时候,如果界面出现一堆红色、黄色的提示,此时心里肯定是飘过一万只草泥马。这个时候我们可以通过Inspection的设置关闭实时检测功能。
1. 通过右键快速关闭(打开)所有规则的实时检测功能

2. 通过Settings >> Editor >> Inspections 进行手动设置

也可以关闭某条规则的实时检测功能或者修改提示级别。
### 代码扫描
可以通过右键菜单、Toolbar按钮、快捷键三种方式手动触发代码检测。同时结果面板中可以对部分实现了QuickFix功能的规则进行快速修复。
#### 触发扫描
在当前编辑的文件中点击右键,可以在弹出的菜单中触发对该文件的检测。

在左侧的Project目录树种点击右键,可以触发对整个工程或者选择的某个目录、文件进行检测。

如果您打开了IDE的Toolbar,也可以通过Toolbar中的按钮来触发检测,目前Toolbar的按钮触发的检测范围与您IDE当时的焦点有关,如当前编辑的文件或者是Project目录树选中的项,是不是感觉与右键菜单的检测范围类似呢。

使用快捷键(Ctrl+Shift+Alt+J)触发弹出窗口,选择检测范围;您也可自定义快捷键。


#### 扫描结果
检测结果直接使用IDEA Run Inspection By Name功能的结果界面,插件的检测结果分级为Blocker、Critical、Major。默认按等级分组,方便统计每个级别错误的数量。

默认情况我们在结果面板需要双击具体违规项才能打开对应的源文件,开启Autoscroll To Source选项,单击面板中的文件名、或者是具体的违规项的时候IDEA会自动打开对应的源文件。

#### QuickFix
对于实现Quick Fix的规则,在结果面板中可以直接一键修复 `注意:IDEA14、15可以通过左下角的灯泡进行一键修复操作。`


#### 其他
面板中其他按钮的功能大家自行探索吧,就不一一赘述了
### 代码提交时检测
1. 在提交代码框勾选Alibaba Code Guidelines选项

2. 如果有违反手册的地方会提示是否继续提交,选择取消后会自动对修改的代码进行扫描

================================================
FILE: idea-plugin/build.gradle
================================================
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'
}
}
================================================
FILE: idea-plugin/gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
================================================
FILE: idea-plugin/gradle.properties
================================================
kotlin_version=1.3.72
idea_version=2018.3
plugin_name=Alibaba Java Coding Guidelines
gradle_jetbrains_version=0.4.5
systemProp.file.encoding=UTF-8
plugin_version=2.1.0
================================================
FILE: idea-plugin/gradlew
================================================
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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
#
# https://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.
#
##############################################################################
##
## 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='"-Xmx64m" "-Xms64m"'
# 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 or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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"
exec "$JAVACMD" "$@"
================================================
FILE: idea-plugin/gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@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 Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@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="-Xmx64m" "-Xms64m"
@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
================================================
FILE: idea-plugin/p3c-common/build.gradle
================================================
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.1.0'
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
}
================================================
FILE: idea-plugin/p3c-common/src/main/java/icons/P3cIcons.java
================================================
/*
* 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");
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/AliInspectionAction.kt
================================================
/*
* 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(CommonDataKeys.PSI_ELEMENT)
val psiFile = e.getData(CommonDataKeys.PSI_FILE)
val virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE)
val virtualFiles = e.getData>(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(*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>, 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>,
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)
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/PmdGlobalInspectionContextImpl.kt
================================================
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.ProblemHighlightFilter
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.ReadAction
import com.intellij.openapi.application.ex.ApplicationManagerEx
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Document
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.Task.Backgroundable
import com.intellij.openapi.progress.impl.CoreProgressManager
import com.intellij.openapi.progress.util.ProgressIndicatorUtils
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.displayUrlRelativeToProject
import com.intellij.openapi.project.isProjectOrWorkspaceFile
import com.intellij.openapi.roots.FileIndex
import com.intellij.openapi.roots.ProjectRootManager
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.PsiBinaryFile
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.SingleRootFileViewProvider
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,
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 { scope.toSearchScope() }
val localScopeFiles: MutableSet? = if (searchScope is LocalSearchScope) THashSet() else null
val filesToInspect: BlockingQueue = ArrayBlockingQueue(1000)
val iteratingIndicator: ProgressIndicator = SensitiveProgressWrapper(progressIndicator)
val future: Future<*> = startIterateScopeInBackground(
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 = 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 startIterateScopeInBackground(
scope: AnalysisScope,
localScopeFiles: MutableCollection?,
headlessEnvironment: Boolean,
outFilesToInspect: BlockingQueue,
progressIndicator: ProgressIndicator
): Future<*>? {
val task: Backgroundable = object : Backgroundable(project, "Scanning Files to Inspect") {
override fun run(indicator: ProgressIndicator) {
try {
val fileIndex: FileIndex = ProjectRootManager.getInstance(project).fileIndex
scope.accept { file: VirtualFile? ->
ProgressManager.checkCanceled()
if (isProjectOrWorkspaceFile(file!!) || !fileIndex.isInContent(file)) return@accept true
val psiFile =
ReadAction.compute {
if (project.isDisposed) throw ProcessCanceledException()
val psi = PsiManager.getInstance(project).findFile(file)
val document =
psi?.let { shouldProcess(it, headlessEnvironment, localScopeFiles) }
if (document != null) {
return@compute psi
}
null
}
// do not inspect binary files
if (psiFile != null) {
try {
check(!ApplicationManager.getApplication().isReadAccessAllowed) { "Must not have read action" }
outFilesToInspect.put(psiFile)
} catch (e: InterruptedException) {
logger.error(e)
}
}
ProgressManager.checkCanceled()
true
}
} catch (e: ProcessCanceledException) {
// ignore, but put tombstone
} finally {
try {
outFilesToInspect.put(PsiUtilCore.NULL_PSI_FILE)
} catch (e: InterruptedException) {
logger.error(e)
}
}
}
}
return (ProgressManager.getInstance() as CoreProgressManager).runProcessWithProgressAsynchronously(
task,
progressIndicator,
null
)
}
private fun shouldProcess(
file: PsiFile,
headlessEnvironment: Boolean,
localScopeFiles: MutableCollection?
): Document? {
val virtualFile = file.virtualFile ?: return null
if (isBinary(file)) return null //do not inspect binary files
if (isViewClosed && !headlessEnvironment) {
throw ProcessCanceledException()
}
if (logger.isDebugEnabled) {
logger.debug("Running local inspections on " + virtualFile.path)
}
if (SingleRootFileViewProvider.isTooLargeForIntelligence(virtualFile)) return null
if (localScopeFiles != null && !localScopeFiles.add(virtualFile)) return null
return if (!ProblemHighlightFilter.shouldProcessFileInBatch(file)) null else PsiDocumentManager.getInstance(
project
).getDocument(file)
}
private fun isBinary(file: PsiFile): Boolean {
return file is PsiBinaryFile || file.fileType.isBinary
}
private fun doPmdProcess(
file: PsiFile,
aliProjectComponent: AliProjectComponent,
virtualFile: VirtualFile
) {
val url: String = 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>()
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)
}
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/SwitchLanguageAction.kt
================================================
/*
* 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}")
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/action/ToggleProjectInspectionAction.kt
================================================
/*
* 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")
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/compatible/inspection/InspectionProfileService.kt
================================================
/*
* 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>,
managerEx: InspectionManagerEx, psiElement: PsiElement?): InspectionProfileImpl {
val profile = getProjectInspectionProfile(managerEx.project)
val allWrappers: LinkedHashSet> = 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>, 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
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/compatible/inspection/Inspections.kt
================================================
/*
* 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> {
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> {
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).map { it.tool }
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/component/AliProjectComponent.kt
================================================
/*
* 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()
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>? = 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
}
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/component/CommonSettingsApplicationComponent.kt
================================================
/*
* 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)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/config/P3cConfig.kt
================================================
/*
* 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 {
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!!
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/config/SmartFoxProjectConfig.kt
================================================
/*
* 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.util.xmlb.XmlSerializerUtil
/**
*
*
* @author caikang
* @date 2017/03/01
*/
@State(name = "SmartFoxProjectConfig", storages = [com.intellij.openapi.components.Storage(file = "smartfox_info.xml")])
class SmartFoxProjectConfig : PersistentStateComponent {
var projectInspectionClosed = false
override fun getState(): SmartFoxProjectConfig? {
return this
}
override fun loadState(state: SmartFoxProjectConfig) {
XmlSerializerUtil.copyBean(state, this)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/ep/InspectionActionExtensionPoint.kt
================================================
/*
* 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.ep
import com.alibaba.smartfox.idea.common.util.PluginVersions
import com.intellij.codeInspection.ex.GlobalInspectionContextImpl
import com.intellij.codeInspection.ui.InspectionResultsView
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.project.Project
/**
*
*
* @author caikang
* @date 2017/06/19
*/
interface InspectionActionExtensionPoint {
fun doOnInspectionFinished(context: GlobalInspectionContextImpl, projectScopeSelected: Boolean) {}
fun doOnClose(noSuspiciousCodeFound: Boolean, project: Project?) {}
fun doOnView(view: InspectionResultsView) {}
companion object {
val extension = ExtensionPointName.create(
"${PluginVersions.pluginId.idString}.inspectionAction")!!
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/ep/package-info.java
================================================
/**
* extension point
*
* @author caikang
* @date 2017/06/19
*/
package com.alibaba.p3c.idea.ep;
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/i18n/P3cBundle.kt
================================================
/*
* 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.i18n
import com.alibaba.p3c.idea.config.P3cConfig
import com.alibaba.p3c.pmd.I18nResources
import com.alibaba.smartfox.idea.common.util.getService
import com.intellij.CommonBundle
import java.util.Locale
import java.util.ResourceBundle
/**
*
*
* @author caikang
* @date 2017/06/20
*/
object P3cBundle {
private val p3cConfig = P3cConfig::class.java.getService()
private val resourceBundle = ResourceBundle.getBundle("messages.P3cBundle",
Locale(p3cConfig.locale), I18nResources.XmlControl())
fun getMessage(key: String): String {
return resourceBundle.getString(key).trim()
}
fun message(key: String, vararg params: Any): String {
return CommonBundle.message(resourceBundle, key, *params).trim()
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliAccessToNonThreadSafeStaticFieldFromInstanceInspection.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.siyeh.ig.threading.AccessToNonThreadSafeStaticFieldFromInstanceInspection
/**
* @author caikang
* @date 2016/12/08
*/
class AliAccessToNonThreadSafeStaticFieldFromInstanceInspection
: AccessToNonThreadSafeStaticFieldFromInstanceInspection,
AliBaseInspection {
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
init {
nonThreadSafeClasses.clear()
nonThreadSafeClasses.add("java.text.SimpleDateFormat")
}
override fun ruleName(): String {
return "AvoidCallStaticSimpleDateFormatRule"
}
override fun getDisplayName(): String {
return RuleInspectionUtils.getRuleMessage(ruleName())
}
override fun buildErrorString(vararg infos: Any): String {
return P3cBundle.getMessage("com.alibaba.p3c.idea.inspection.rule.AvoidCallStaticSimpleDateFormatRule.errMsg")
}
override fun getStaticDescription(): String? {
return RuleInspectionUtils.getRuleStaticDescription(ruleName())
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliArrayNamingShouldHaveBracketInspection.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiParameter
import com.siyeh.ig.InspectionGadgetsFix
import com.siyeh.ig.style.CStyleArrayDeclarationInspection
import javax.swing.JComponent
/**
*
* Batch QuickFix Supported
* @author caikang
* @date 2017/02/26
*/
class AliArrayNamingShouldHaveBracketInspection : CStyleArrayDeclarationInspection, AliBaseInspection {
constructor()
/**
* ForJavassist
*/
constructor(any: Any?) : this()
override fun ruleName(): String {
return "ArrayNamingShouldHaveBracketRule"
}
override fun getDisplayName(): String {
return RuleInspectionUtils.getRuleMessage(ruleName())
}
override fun getShortName(): String {
return "AliArrayNamingShouldHaveBracket"
}
override fun getStaticDescription(): String? {
return RuleInspectionUtils.getRuleStaticDescription(ruleName())
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())
}
override fun createOptionsPanel(): JComponent? {
return null
}
override fun buildErrorString(vararg infos: Any?): String {
val info = infos[0]
if (info is PsiMethod) {
return displayName
}
val choice = if (info is PsiField) 1 else if (info is PsiParameter) 2 else 3
return P3cBundle.message("com.alibaba.p3c.idea.inspection.rule.ArrayNamingShouldHaveBracketRule.errMsg", choice)
}
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {
val fix = super.buildFix(*infos) ?: return null
return DecorateInspectionGadgetsFix(fix,
P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.ArrayNamingShouldHaveBracketRule"))
}
override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {
return buildFix(psiElement)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliBaseInspection.kt
================================================
/*
* 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.inspection
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
/**
* @author caikang
* @date 2016/12/08
*/
interface AliBaseInspection {
/**
* ruleName
* @return ruleName
*/
fun ruleName(): String
/**
* display info for inspection
* @return display
*/
fun getDisplayName(): String
/**
* group display info for inspection
* @return group display
*/
fun getGroupDisplayName(): String
/**
* inspection enable by default
* @return true -> enable
*/
fun isEnabledByDefault(): Boolean
/**
* default inspection level
* @return level
*/
fun getDefaultLevel(): HighlightDisplayLevel
/**
* inspection short name
* @return shor name
*/
fun getShortName(): String
fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? = null
fun manualParsePsiElement(psiFile: PsiFile, manager: InspectionManager,
start: Int, end: Int): PsiElement {
return psiFile.findElementAt(start)!!
}
companion object {
val GROUP_NAME = "Ali-Check"
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliControlFlowStatementWithoutBracesInspection.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.psi.PsiElement
import com.siyeh.ig.InspectionGadgetsFix
import com.siyeh.ig.style.ControlFlowStatementWithoutBracesInspection
/**
* Batch QuickFix Supported
* @author caikang
* @date 2016/12/15
*/
class AliControlFlowStatementWithoutBracesInspection
: ControlFlowStatementWithoutBracesInspection,
AliBaseInspection {
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
override fun ruleName(): String {
return "NeedBraceRule"
}
override fun getDisplayName(): String {
return RuleInspectionUtils.getRuleMessage(ruleName())
}
override fun buildErrorString(vararg infos: Any): String {
return P3cBundle.getMessage("com.alibaba.p3c.idea.inspection.rule.NeedBraceRule.errMsg")
}
override fun getStaticDescription(): String? {
return RuleInspectionUtils.getRuleStaticDescription(ruleName())
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())
}
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {
val fix = super.buildFix(*infos) ?: return null
return DecorateInspectionGadgetsFix(fix, P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.NeedBraceRule"))
}
override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {
return buildFix(psiElement)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliEqualsAvoidNullInspection.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiExpression
import com.intellij.psi.PsiField
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiLiteralExpression
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiReferenceExpression
import com.siyeh.HardcodedMethodConstants
import com.siyeh.ig.BaseInspectionVisitor
import com.siyeh.ig.InspectionGadgetsFix
import com.siyeh.ig.psiutils.TypeUtils
import com.siyeh.ig.style.LiteralAsArgToStringEqualsInspection
import org.jetbrains.annotations.NonNls
/**
*
* Batch QuickFix Supported
* @author caikang
* @date 2017/02/27
*/
class AliEqualsAvoidNullInspection : LiteralAsArgToStringEqualsInspection, AliBaseInspection {
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
override fun ruleName(): String {
return "EqualsAvoidNullRule"
}
override fun getDisplayName(): String {
return RuleInspectionUtils.getRuleMessage(ruleName())
}
override fun buildErrorString(vararg infos: Any?): String {
val methodName = infos[0] as String
return String.format(P3cBundle.getMessage("com.alibaba.p3c.idea.inspection.rule.AliEqualsAvoidNull.errMsg"),
methodName)
}
override fun getShortName(): String {
return "AliEqualsAvoidNull"
}
override fun getStaticDescription(): String? {
return RuleInspectionUtils.getRuleStaticDescription(ruleName())
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())
}
override fun buildVisitor(): BaseInspectionVisitor {
return LiteralAsArgToEqualsVisitor()
}
private class LiteralAsArgToEqualsVisitor : BaseInspectionVisitor() {
override fun visitMethodCallExpression(
expression: PsiMethodCallExpression) {
super.visitMethodCallExpression(expression)
val methodExpression = expression.methodExpression
@NonNls val methodName = methodExpression.referenceName
if (HardcodedMethodConstants.EQUALS != methodName && HardcodedMethodConstants.EQUALS_IGNORE_CASE != methodName) {
return
}
val argList = expression.argumentList
val args = argList.expressions
if (args.size != 1) {
return
}
val argument = args[0]
val argumentType = argument.type ?: return
if (argument !is PsiLiteralExpression && !isConstantField(argument)) {
return
}
if (!TypeUtils.isJavaLangString(argumentType)) {
return
}
val target = methodExpression.qualifierExpression
if (target is PsiLiteralExpression || isConstantField(argument)) {
return
}
registerError(argument, methodName)
}
private fun isConstantField(argument: PsiExpression): Boolean {
if (argument !is PsiReferenceExpression) {
return false
}
val psiField = argument.resolve() as? PsiField ?: return false
val modifierList = psiField.modifierList ?: return false
return modifierList.hasModifierProperty("final") && modifierList.hasModifierProperty("static")
}
}
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {
val fix = super.buildFix(*infos) ?: return null
return DecorateInspectionGadgetsFix(fix,
P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.AliEqualsAvoidNull"))
}
override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {
return buildFix(psiElement)
}
override fun manualParsePsiElement(psiFile: PsiFile, manager: InspectionManager, start: Int, end: Int): PsiElement {
return psiFile.findElementAt(start)!!.parent.parent
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliLocalInspectionToolProvider.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.config.P3cConfig
import com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection
import com.alibaba.p3c.idea.inspection.standalone.AliDeprecationInspection
import com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection
import com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection
import com.alibaba.p3c.pmd.I18nResources
import com.alibaba.smartfox.idea.common.util.getService
import com.beust.jcommander.internal.Lists
import com.beust.jcommander.internal.Maps
import com.intellij.codeInspection.InspectionToolProvider
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.psi.PsiCompiledFile
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiImportList
import com.intellij.psi.PsiJavaFile
import javassist.CannotCompileException
import javassist.ClassClassPath
import javassist.ClassPool
import javassist.CtField
import javassist.NotFoundException
import net.sourceforge.pmd.Rule
import net.sourceforge.pmd.RuleSet
import net.sourceforge.pmd.RuleSetFactory
import net.sourceforge.pmd.RuleSetNotFoundException
import net.sourceforge.pmd.RuleSets
import javax.annotation.Generated
/**
* @author caikang
* @date 2016/12/16
*/
class AliLocalInspectionToolProvider : InspectionToolProvider {
override fun getInspectionClasses(): Array> {
return CLASS_LIST.toTypedArray()
}
interface ShouldInspectChecker {
/**
* check inspect whether or not
* @param file file to inspect
* @return true or false
*/
fun shouldInspect(file: PsiFile): Boolean
}
class RuleInfo(var rule: Rule, var shouldInspectChecker: ShouldInspectChecker)
companion object {
val ruleInfoMap: MutableMap = Maps.newHashMap()
private val LOGGER = Logger.getInstance(AliLocalInspectionToolProvider::class.java)
val ruleNames: MutableList = Lists.newArrayList()!!
private val CLASS_LIST = Lists.newArrayList>()
private val nativeInspectionToolClass = arrayListOf>(
AliMissingOverrideAnnotationInspection::class.java,
AliAccessStaticViaInstanceInspection::class.java,
AliDeprecationInspection::class.java,
MapOrSetKeyShouldOverrideHashCodeEqualsInspection::class.java,
AliArrayNamingShouldHaveBracketInspection::class.java,
AliControlFlowStatementWithoutBracesInspection::class.java,
AliEqualsAvoidNullInspection::class.java,
AliLongLiteralsEndingWithLowercaseLInspection::class.java,
AliWrapperTypeEqualityInspection::class.java
)
val javaShouldInspectChecker = object : ShouldInspectChecker {
override fun shouldInspect(file: PsiFile): Boolean {
val basicInspect = file is PsiJavaFile && file !is PsiCompiledFile
if (!basicInspect) {
return false
}
if (!validScope(file)) {
return false
}
val importList = file.children.firstOrNull {
it is PsiImportList
} as? PsiImportList ?: return true
return !importList.allImportStatements.any {
it.text.contains(Generated::class.java.name)
}
}
private fun validScope(file: PsiFile): Boolean {
val virtualFile = file.virtualFile
val index = ProjectRootManager.getInstance(file.project).fileIndex
return index.isInSource(virtualFile)
&& !index.isInTestSourceContent(virtualFile)
&& !index.isInLibraryClasses(virtualFile)
&& !index.isInLibrarySource(virtualFile)
}
}
init {
I18nResources.changeLanguage(P3cConfig::class.java.getService().locale)
Thread.currentThread().contextClassLoader = AliLocalInspectionToolProvider::class.java.classLoader
initPmdInspection()
initNativeInspection()
}
private fun initNativeInspection() {
val pool = ClassPool.getDefault()
pool.insertClassPath(ClassClassPath(DelegateLocalInspectionTool::class.java))
nativeInspectionToolClass.forEach {
pool.insertClassPath(ClassClassPath(it))
val cc = pool.get(DelegateLocalInspectionTool::class.java.name)
cc.name = "Delegate${it.simpleName}"
val ctField = cc.getField("forJavassist")
cc.removeField(ctField)
val itClass = pool.get(it.name)
val toolClass = pool.get(LocalInspectionTool::class.java.name)
val newField = CtField(toolClass, "forJavassist", cc)
cc.addField(newField, CtField.Initializer.byNew(itClass))
CLASS_LIST.add(cc.toClass() as Class)
}
}
private fun initPmdInspection() {
for (ri in newRuleInfos()) {
this.ruleNames.add(ri.rule.name)
ruleInfoMap.put(ri.rule.name, ri)
}
val pool = ClassPool.getDefault()
pool.insertClassPath(ClassClassPath(DelegatePmdInspection::class.java))
try {
for (ruleInfo in ruleInfoMap.values) {
val cc = pool.get(DelegatePmdInspection::class.java.name)
cc.name = ruleInfo.rule.name + "Inspection"
val ctField = cc.getField("ruleName")
cc.removeField(ctField)
val value = "\"" + ruleInfo.rule.name + "\""
val newField = CtField.make("private String ruleName = $value;", cc)
cc.addField(newField, value)
CLASS_LIST.add(cc.toClass() as Class)
}
} catch (e: NotFoundException) {
LOGGER.error(e)
} catch (e: CannotCompileException) {
LOGGER.error(e)
}
}
private fun newRuleInfos(): List {
val result = Lists.newArrayList()
result.addAll(processForRuleSet("java/ali-pmd", javaShouldInspectChecker))
result.addAll(processForRuleSet("vm/ali-other", object : ShouldInspectChecker {
override fun shouldInspect(file: PsiFile): Boolean {
val virtualFile = file.virtualFile ?: return false
val path = virtualFile.canonicalPath
return path != null && path.endsWith(".vm")
}
}))
return result
}
fun getRuleSet(ruleSetName: String): RuleSet {
val factory = RuleSetFactory()
return factory.createRuleSet(ruleSetName.replace("/", "-"))
}
fun getRuleSetList(): List {
return listOf(getRuleSet("java/ali-pmd"), getRuleSet("vm/ali-other"))
}
fun getRuleSets(): RuleSets {
return RuleSets().also { rs ->
for (ruleSet in getRuleSetList()) {
rs.addRuleSet(ruleSet)
}
}
}
private fun processForRuleSet(ruleSetName: String, shouldInspectChecker: ShouldInspectChecker): List {
val result = Lists.newArrayList()
try {
val ruleSet = getRuleSet(ruleSetName)
ruleSet.rules.mapTo(result) {
RuleInfo(it, shouldInspectChecker)
}
} catch (e: RuleSetNotFoundException) {
LOGGER.error(String.format("rule set %s not found for", ruleSetName))
}
return result
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliLongLiteralsEndingWithLowercaseLInspection.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.siyeh.ig.InspectionGadgetsFix
import com.siyeh.ig.numeric.LongLiteralsEndingWithLowercaseLInspection
/**
*
* Batch QuickFix Supported
* @author caikang
* @date 2017/01/20
*/
class AliLongLiteralsEndingWithLowercaseLInspection : LongLiteralsEndingWithLowercaseLInspection, AliBaseInspection {
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
override fun ruleName(): String {
return "UpperEllRule"
}
override fun getDisplayName(): String {
return RuleInspectionUtils.getRuleMessage(ruleName())
}
override fun buildErrorString(vararg infos: Any?): String {
return P3cBundle.getMessage("com.alibaba.p3c.idea.inspection.rule.AliLongLiteralsEndingWithLowercaseL.errMsg")
}
override fun getShortName(): String {
return "AliLongLiteralsEndingWithLowercaseL"
}
override fun getStaticDescription(): String? {
return RuleInspectionUtils.getRuleStaticDescription(ruleName())
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())
}
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {
val fix = super.buildFix(*infos) ?: return null
return DecorateInspectionGadgetsFix(fix,
P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.AliLongLiteralsEndingWithLowercaseL"))
}
override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {
return buildFix(psiElement)
}
override fun manualParsePsiElement(psiFile: PsiFile, manager: InspectionManager, start: Int, end: Int): PsiElement {
return psiFile.findElementAt(start)!!.parent
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliPmdInspection.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.inspection.AliLocalInspectionToolProvider.ShouldInspectChecker
import com.alibaba.p3c.idea.util.NumberConstants
import com.alibaba.p3c.idea.util.QuickFixes
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import net.sourceforge.pmd.Rule
import org.jetbrains.annotations.Nls
/**
* @author caikang
* @date 2016/12/16
*/
class AliPmdInspection(private val ruleName: String) : LocalInspectionTool(),
AliBaseInspection,
PmdRuleInspectionIdentify {
override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {
return QuickFixes.getQuickFix(ruleName, isOnTheFly)
}
private val staticDescription: String = RuleInspectionUtils.getRuleStaticDescription(ruleName)
private val displayName: String
private val shouldInspectChecker: ShouldInspectChecker
private val defaultLevel: HighlightDisplayLevel
private val rule: Rule
init {
val ruleInfo = AliLocalInspectionToolProvider.ruleInfoMap[ruleName]!!
shouldInspectChecker = ruleInfo.shouldInspectChecker
rule = ruleInfo.rule
displayName = rule.message
defaultLevel = RuleInspectionUtils.getHighlightDisplayLevel(rule.priority)
}
override fun runForWholeFile(): Boolean {
return true
}
override fun checkFile(
file: PsiFile, manager: InspectionManager,
isOnTheFly: Boolean
): Array? {
if (!shouldInspectChecker.shouldInspect(file)) {
return null
}
return AliPmdInspectionInvoker.invokeInspection(file, manager, rule, isOnTheFly)
}
override fun getStaticDescription(): String? {
return staticDescription
}
override fun ruleName(): String {
return ruleName
}
@Nls
override fun getDisplayName(): String {
return displayName
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return defaultLevel
}
@Nls
override fun getGroupDisplayName(): String {
return AliBaseInspection.GROUP_NAME
}
override fun isEnabledByDefault(): Boolean {
return true
}
override fun getShortName(): String {
var shortName = "Alibaba" + ruleName
val index = shortName.lastIndexOf("Rule")
if (index > NumberConstants.INDEX_0) {
shortName = shortName.substring(NumberConstants.INDEX_0, index)
}
return shortName
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliPmdInspectionInvoker.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.component.AliProjectComponent
import com.alibaba.p3c.idea.config.P3cConfig
import com.alibaba.p3c.idea.pmd.AliPmdProcessor
import com.alibaba.p3c.idea.util.DocumentUtils.calculateLineStart
import com.alibaba.p3c.idea.util.DocumentUtils.calculateRealOffset
import com.alibaba.p3c.idea.util.ProblemsUtils
import com.alibaba.p3c.pmd.lang.java.rule.comment.RemoveCommentedCodeRule
import com.beust.jcommander.internal.Lists
import com.google.common.cache.Cache
import com.google.common.cache.CacheBuilder
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import net.sourceforge.pmd.Rule
import net.sourceforge.pmd.RuleViolation
import java.util.concurrent.TimeUnit
/**
* @author caikang
* @date 2016/12/13
*/
class AliPmdInspectionInvoker(
private val psiFile: PsiFile,
private val manager: InspectionManager,
private val rule: Rule
) {
private val logger = Logger.getInstance(javaClass)
private var violations: List = emptyList()
fun doInvoke(isOnTheFly: Boolean) {
Thread.currentThread().contextClassLoader = javaClass.classLoader
val processor = AliPmdProcessor(rule)
val start = System.currentTimeMillis()
val aliProjectComponent = manager.project.getComponent(AliProjectComponent::class.java)
val fileContext = aliProjectComponent.getFileContext(psiFile.virtualFile)
val ruleViolations = fileContext?.ruleViolations
violations = if (isOnTheFly || ruleViolations == null) {
processor.processFile(psiFile, isOnTheFly)
} else {
ruleViolations[rule.name] ?: emptyList()
}
logger.debug(
"elapsed ${System.currentTimeMillis() - start}ms to" +
" to apply rule ${rule.name} for file ${psiFile.virtualFile.canonicalPath}"
)
}
fun getRuleProblems(isOnTheFly: Boolean): Array? {
if (violations.isEmpty()) {
return null
}
val problemDescriptors = Lists.newArrayList(violations.size)
for (rv in violations) {
val virtualFile = LocalFileSystem.getInstance().findFileByPath(rv.filename) ?: continue
val psiFile = PsiManager.getInstance(manager.project).findFile(virtualFile) ?: continue
val document = FileDocumentManager.getInstance().getDocument(virtualFile) ?: continue
val offsets = if (rv.rule.name == RemoveCommentedCodeRule::class.java.simpleName) {
Offsets(
calculateLineStart(document, rv.beginLine),
calculateLineStart(document, rv.endLine + 1) - 1
)
} else {
Offsets(
calculateRealOffset(document, rv.beginLine, rv.beginColumn),
calculateRealOffset(document, rv.endLine, rv.endColumn)
)
}
val errorMessage = if (isOnTheFly) {
rv.description
} else {
"${rv.description} (line ${rv.beginLine})"
}
val problemDescriptor = ProblemsUtils.createProblemDescriptorForPmdRule(
psiFile, manager,
isOnTheFly, rv.rule.name, errorMessage, offsets.start, offsets.end, rv.beginLine
) ?: continue
problemDescriptors.add(problemDescriptor)
}
return problemDescriptors.toTypedArray()
}
companion object {
private lateinit var invokers: Cache
val smartFoxConfig = ServiceManager.getService(P3cConfig::class.java)!!
init {
reInitInvokers(smartFoxConfig.ruleCacheTime)
}
fun invokeInspection(
psiFile: PsiFile?, manager: InspectionManager, rule: Rule,
isOnTheFly: Boolean
): Array? {
if (psiFile == null) {
return null
}
val virtualFile = psiFile.virtualFile ?: return null
if (!smartFoxConfig.ruleCacheEnable) {
val invoker = AliPmdInspectionInvoker(psiFile, manager, rule)
invoker.doInvoke(isOnTheFly)
return invoker.getRuleProblems(isOnTheFly)
}
var invoker = invokers.getIfPresent(FileRule(virtualFile.canonicalPath!!, rule.name))
if (invoker == null) {
synchronized(virtualFile) {
invoker = invokers.getIfPresent(virtualFile.canonicalPath!!)
if (invoker == null) {
invoker = AliPmdInspectionInvoker(psiFile, manager, rule)
invoker!!.doInvoke(isOnTheFly)
invokers.put(FileRule(virtualFile.canonicalPath!!, rule.name), invoker!!)
}
}
}
return invoker!!.getRuleProblems(isOnTheFly)
}
private fun doInvokeIfPresent(filePath: String, rule: String, isOnTheFly: Boolean) {
invokers.getIfPresent(FileRule(filePath, rule))?.doInvoke(isOnTheFly)
}
fun refreshFileViolationsCache(file: VirtualFile) {
AliLocalInspectionToolProvider.ruleNames.forEach {
doInvokeIfPresent(file.canonicalPath!!, it, false)
}
}
fun reInitInvokers(expireTime: Long) {
invokers = CacheBuilder.newBuilder().maximumSize(500).expireAfterWrite(
expireTime,
TimeUnit.MILLISECONDS
).build()!!
}
}
}
data class FileRule(val filePath: String, val ruleName: String)
data class Offsets(val start: Int, val end: Int)
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/AliWrapperTypeEqualityInspection.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.CommonClassNames
import com.intellij.psi.JavaTokenType
import com.intellij.psi.PsiArrayType
import com.intellij.psi.PsiBinaryExpression
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiExpression
import com.intellij.util.IncorrectOperationException
import com.siyeh.ig.BaseInspection
import com.siyeh.ig.BaseInspectionVisitor
import com.siyeh.ig.InspectionGadgetsFix
import com.siyeh.ig.PsiReplacementUtil
import com.siyeh.ig.fixes.EqualityToEqualsFix
import com.siyeh.ig.psiutils.ComparisonUtils
import com.siyeh.ig.psiutils.TypeUtils
import org.jetbrains.annotations.NonNls
/**
*
* Batch QuickFix Supported
* @author caikang
* @date 2017/02/27
*/
class AliWrapperTypeEqualityInspection : BaseInspection, AliBaseInspection {
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
val familyName = "$replaceWith equals"
override fun buildErrorString(vararg infos: Any?): String {
return P3cBundle.getMessage("com.alibaba.p3c.idea.inspection.rule.WrapperTypeEqualityRule.errMsg")
}
override fun buildVisitor(): BaseInspectionVisitor {
return ObjectComparisonVisitor()
}
override fun ruleName(): String {
return "WrapperTypeEqualityRule"
}
override fun getDisplayName(): String {
return RuleInspectionUtils.getRuleMessage(ruleName())
}
override fun getShortName(): String {
return "AliWrapperTypeEquality"
}
override fun getStaticDescription(): String? {
return RuleInspectionUtils.getRuleStaticDescription(ruleName())
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return RuleInspectionUtils.getHighlightDisplayLevel(ruleName())
}
public override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {
if (infos.isEmpty()) {
return DecorateInspectionGadgetsFix(EqualityToEqualsFix(), familyName)
}
val type = infos[0] as PsiArrayType
val componentType = type.componentType
val fix = ArrayEqualityFix(componentType is PsiArrayType, familyName)
return DecorateInspectionGadgetsFix(fix, fix.name, familyName)
}
private inner class ObjectComparisonVisitor : BaseInspectionVisitor() {
override fun visitBinaryExpression(expression: PsiBinaryExpression) {
if (!ComparisonUtils.isEqualityComparison(expression)) {
return
}
checkForWrapper(expression)
}
private fun checkForWrapper(expression: PsiBinaryExpression) {
val rhs = expression.rOperand ?: return
val lhs = expression.lOperand
if (!isWrapperType(lhs) || !isWrapperType(rhs)) {
return
}
registerError(expression.operationSign)
}
private fun isWrapperType(expression: PsiExpression): Boolean {
if (hasNumberType(expression)) {
return true
}
return TypeUtils.expressionHasTypeOrSubtype(expression, CommonClassNames.JAVA_LANG_BOOLEAN)
|| TypeUtils.expressionHasTypeOrSubtype(expression, CommonClassNames.JAVA_LANG_CHARACTER)
}
private fun hasNumberType(expression: PsiExpression): Boolean {
return TypeUtils.expressionHasTypeOrSubtype(expression, CommonClassNames.JAVA_LANG_NUMBER)
}
/**
* checkForNumber end
*/
}
private class ArrayEqualityFix(private val deepEquals: Boolean, private val familyName: String) :
InspectionGadgetsFix() {
override fun getName(): String {
if (deepEquals) {
return "$replaceWith 'Arrays.deepEquals()'"
} else {
return "$replaceWith 'Arrays.equals()'"
}
}
override fun getFamilyName(): String {
return familyName
}
@Throws(IncorrectOperationException::class)
override fun doFix(project: Project, descriptor: ProblemDescriptor) {
val element = descriptor.psiElement
val parent = element.parent as? PsiBinaryExpression ?: return
val tokenType = parent.operationTokenType
@NonNls
val newExpressionText = StringBuilder()
if (JavaTokenType.NE == tokenType) {
newExpressionText.append('!')
} else if (JavaTokenType.EQEQ != tokenType) {
return
}
if (deepEquals) {
newExpressionText.append("java.util.Arrays.deepEquals(")
} else {
newExpressionText.append("java.util.Arrays.equals(")
}
newExpressionText.append(parent.lOperand.text)
newExpressionText.append(',')
val rhs = parent.rOperand ?: return
newExpressionText.append(rhs.text)
newExpressionText.append(')')
PsiReplacementUtil.replaceExpressionAndShorten(
parent,
newExpressionText.toString()
)
}
}
override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? {
val expression = psiElement.parent as? PsiBinaryExpression ?: return null
val rhs = expression.rOperand ?: return null
val lhs = expression.lOperand
val lhsType = lhs.type
if (lhsType !is PsiArrayType || rhs.type !is PsiArrayType) {
return buildFix()
}
return buildFix(lhsType)
}
companion object {
val replaceWith = P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.replace.with")
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/DelegateLocalInspectionTool.kt
================================================
/*
* 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.inspection
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiFile
import org.jetbrains.annotations.Nls
/**
*
* @author caikang
* @date 2017/07/19
*/
class DelegateLocalInspectionTool : LocalInspectionTool(), AliBaseInspection {
private val forJavassist: LocalInspectionTool? = null
private val localInspectionTool: LocalInspectionTool
init {
localInspectionTool = forJavassist ?: throw IllegalStateException()
}
override fun runForWholeFile(): Boolean {
return localInspectionTool.runForWholeFile()
}
override fun checkFile(
file: PsiFile, manager: InspectionManager,
isOnTheFly: Boolean
): Array? {
return localInspectionTool.checkFile(file, manager, isOnTheFly)
}
override fun getStaticDescription(): String? {
return localInspectionTool.staticDescription
}
override fun ruleName(): String {
return (localInspectionTool as AliBaseInspection).ruleName()
}
@Nls
override fun getDisplayName(): String {
return localInspectionTool.displayName
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return localInspectionTool.defaultLevel
}
@Nls
override fun getGroupDisplayName(): String {
return AliBaseInspection.GROUP_NAME
}
override fun isEnabledByDefault(): Boolean {
return true
}
override fun getShortName(): String {
return localInspectionTool.shortName
}
override fun isSuppressedFor(element: PsiElement): Boolean {
return localInspectionTool.isSuppressedFor(element)
}
override fun buildVisitor(
holder: ProblemsHolder, isOnTheFly: Boolean,
session: LocalInspectionToolSession
): PsiElementVisitor {
if (!AliLocalInspectionToolProvider.javaShouldInspectChecker.shouldInspect(holder.file)) {
return PsiElementVisitor.EMPTY_VISITOR
}
return localInspectionTool.buildVisitor(holder, isOnTheFly, session)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/DelegatePmdInspection.kt
================================================
/*
* 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.inspection
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.annotations.Nls
/**
* @author caikang
* @date 2017/02/28
*/
class DelegatePmdInspection : LocalInspectionTool(), AliBaseInspection, PmdRuleInspectionIdentify {
private val ruleName: String? = null
private val aliPmdInspection: AliPmdInspection
init {
aliPmdInspection = AliPmdInspection(ruleName!!)
}
override fun runForWholeFile(): Boolean {
return aliPmdInspection.runForWholeFile()
}
override fun checkFile(file: PsiFile, manager: InspectionManager,
isOnTheFly: Boolean): Array? {
return aliPmdInspection.checkFile(file, manager, isOnTheFly)
}
override fun getStaticDescription(): String? {
return aliPmdInspection.staticDescription
}
override fun ruleName(): String {
return ruleName!!
}
@Nls
override fun getDisplayName(): String {
return aliPmdInspection.displayName
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return aliPmdInspection.defaultLevel
}
@Nls
override fun getGroupDisplayName(): String {
return aliPmdInspection.groupDisplayName
}
override fun isEnabledByDefault(): Boolean {
return aliPmdInspection.isEnabledByDefault
}
override fun getShortName(): String {
return aliPmdInspection.shortName
}
override fun isSuppressedFor(element: PsiElement): Boolean {
return aliPmdInspection.isSuppressedFor(element)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/PmdRuleInspectionIdentify.kt
================================================
/*
* 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.inspection
/**
*
*
* @author caikang
* @date 2017/03/16
6
*/
interface PmdRuleInspectionIdentify {
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/RuleInspectionUtils.kt
================================================
/*
* 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.inspection
import com.alibaba.p3c.idea.config.P3cConfig
import com.alibaba.p3c.idea.util.HighlightDisplayLevels
import com.alibaba.p3c.idea.util.NumberConstants
import com.alibaba.p3c.pmd.I18nResources
import com.alibaba.smartfox.idea.common.util.getService
import com.google.common.base.Joiner
import com.google.common.collect.ImmutableMap
import com.google.common.collect.Lists
import com.google.common.collect.Maps
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.io.URLUtil
import freemarker.template.Configuration
import freemarker.template.TemplateException
import net.sourceforge.pmd.Rule
import net.sourceforge.pmd.RulePriority
import net.sourceforge.pmd.RuleSetFactory
import net.sourceforge.pmd.RuleSetNotFoundException
import org.apache.commons.lang3.StringUtils
import java.io.File
import java.io.IOException
import java.io.StringWriter
import java.net.URL
import java.net.URLDecoder
import java.nio.charset.StandardCharsets
import java.util.jar.JarFile
import java.util.regex.Pattern
/**
* @author caikang
* @date 2016/12/16
*/
object RuleInspectionUtils {
private val logger = Logger.getInstance(RuleInspectionUtils::class.java)
private val ruleSetFilePattern = Pattern.compile("(java|vm)/ali-.*?\\.xml")
private val staticDescriptionTemplate = run {
val cfg = Configuration(Configuration.VERSION_2_3_25)
cfg.setClassForTemplateLoading(RuleInspectionUtils::class.java, "/tpl")
cfg.defaultEncoding = "UTF-8"
cfg.getTemplate("StaticDescriptionTemplate.ftl")
}
private val ruleSetsPrefix = "rulesets/"
private val ruleStaticDescriptions: Map
private val ruleMessages: Map
private val displayLevelMap: Map
init {
I18nResources.changeLanguage(P3cConfig::class.java.getService().locale)
val builder = ImmutableMap.builder()
val messageBuilder = ImmutableMap.builder()
val displayLevelBuilder = ImmutableMap.builder()
val rules = loadAllAlibabaRule()
for (rule in rules) {
builder.put(rule.name, parseStaticDescription(rule))
messageBuilder.put(rule.name, rule.message)
displayLevelBuilder.put(rule.name, getHighlightDisplayLevel(rule.priority))
}
ruleStaticDescriptions = builder.build()
ruleMessages = messageBuilder.build()
displayLevelMap = displayLevelBuilder.build()
}
fun getRuleStaticDescription(ruleName: String): String {
return ruleStaticDescriptions[ruleName]!!
}
fun getHighlightDisplayLevel(ruleName: String): HighlightDisplayLevel {
val level = displayLevelMap[ruleName]
return level ?: HighlightDisplayLevel.WEAK_WARNING
}
fun getHighlightDisplayLevel(rulePriority: RulePriority): HighlightDisplayLevel {
when (rulePriority) {
RulePriority.HIGH -> return HighlightDisplayLevels.BLOCKER
RulePriority.MEDIUM_HIGH -> return HighlightDisplayLevels.CRITICAL
else -> return HighlightDisplayLevels.MAJOR
}
}
fun getRuleMessage(ruleName: String): String {
return ruleMessages[ruleName]!!
}
private fun parseStaticDescription(rule: Rule): String {
val writer = StringWriter()
try {
val map = Maps.newHashMap()
map.put("message", StringUtils.trimToEmpty(rule.message))
map.put("description", StringUtils.trimToEmpty(rule.description))
val examples = rule.examples.map {
it?.trim {
c ->
c == '\n'
}
}
map.put("examples", examples)
staticDescriptionTemplate.process(map, writer)
} catch (e: TemplateException) {
logger.error(e)
} catch (e: IOException) {
logger.error(e)
}
return writer.toString()
}
private fun loadAllAlibabaRule(): List {
try {
Thread.currentThread().contextClassLoader = RuleInspectionUtils::class.java.classLoader
val ruleSetConfigs = findRuleSetConfigs()
val ruleSetFactory = RuleSetFactory()
val ruleSets = ruleSetFactory.createRuleSets(
Joiner.on(",").join(ruleSetConfigs).replace("/".toRegex(), "-"))
val map = Maps.newHashMap()
ruleSets.allRuleSets
.asSequence()
.flatMap { it.rules.asSequence() }
.forEach { map.put(it.name, it) }
return Lists.newArrayList(map.values)
} catch (e: IOException) {
logger.warn("no available alibaba rules")
return emptyList()
} catch (e: RuleSetNotFoundException) {
logger.error("rule sets not found", e)
return emptyList()
}
}
@Throws(IOException::class)
private fun findRuleSetConfigs(): List {
val ruleSets = Lists.newArrayList()
val enumeration = RuleInspectionUtils::class.java.classLoader.getResources(ruleSetsPrefix)
while (enumeration.hasMoreElements()) {
val url = enumeration.nextElement()
if (URLUtil.JAR_PROTOCOL == url.protocol) {
findRuleSetsFromJar(ruleSets, url)
} else if (URLUtil.FILE_PROTOCOL == url.protocol) {
findRuleSetsFromDirectory(ruleSets, url)
}
}
return ruleSets
}
@Throws(IOException::class)
private fun findRuleSetsFromDirectory(ruleSets: MutableList, url: URL) {
val file = File(url.path)
if (file.exists() && file.isDirectory) {
val files = Lists.newArrayList()
FileUtil.collectMatchedFiles(file, ruleSetFilePattern, files)
files.mapTo(ruleSets) { it.canonicalPath.replace(url.path, "").replace(".xml", "") }
}
}
@Throws(IOException::class)
private fun findRuleSetsFromJar(ruleSets: MutableList, url: URL) {
logger.info("start to find rule sets from jar " + url)
var path = URLDecoder.decode(url.path, StandardCharsets.UTF_8.name())
val index = path.lastIndexOf(URLUtil.JAR_SEPARATOR)
if (index > NumberConstants.INDEX_0) {
path = path.substring("file:".length, index)
}
val jarFile = JarFile(path)
logger.info("create jarFile for path " + path)
val jarEntries = jarFile.entries()
while (jarEntries.hasMoreElements()) {
val jarEntry = jarEntries.nextElement()
val subPath = jarEntry.name.replace(ruleSetsPrefix, "")
if (ruleSetFilePattern.matcher(subPath).find()) {
val resultPath = subPath.replace(".xml", "")
logger.info("get result rule set " + resultPath)
ruleSets.add(resultPath)
}
}
logger.info("find rule sets from jar $url finished")
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/standalone/AliAccessStaticViaInstanceInspection.kt
================================================
/*
* 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.inspection.standalone
import com.alibaba.p3c.idea.config.P3cConfig
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.inspection.AliBaseInspection
import com.alibaba.p3c.idea.util.HighlightDisplayLevels
import com.alibaba.smartfox.idea.common.util.getService
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil
import com.intellij.codeInsight.daemon.impl.quickfix.AccessStaticViaInstanceFix
import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.codeInspection.accessStaticViaInstance.AccessStaticViaInstance
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.JavaResolveResult
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiPackage
import com.intellij.psi.PsiReferenceExpression
import com.intellij.psi.PsiSubstitutor
import java.util.ArrayList
/**
* @author caikang
* @date 2016/12/08
*/
class AliAccessStaticViaInstanceInspection : AccessStaticViaInstance, AliBaseInspection {
val messageKey = "com.alibaba.p3c.idea.inspection.standalone.AliAccessStaticViaInstanceInspection"
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
override fun getDisplayName(): String {
return P3cBundle.getMessage("$messageKey.message")
}
override fun getStaticDescription(): String? {
return P3cBundle.getMessage("$messageKey.desc")
}
override fun ruleName(): String {
return "AvoidAccessStaticViaInstanceRule"
}
override fun getShortName(): String {
return "AliAccessStaticViaInstance"
}
override fun createAccessStaticViaInstanceFix(expr: PsiReferenceExpression,
onTheFly: Boolean,
result: JavaResolveResult): AccessStaticViaInstanceFix {
return object : AccessStaticViaInstanceFix(expr, result, onTheFly) {
val fixKey = "com.alibaba.p3c.idea.quickfix.standalone.AliAccessStaticViaInstanceInspection"
internal val text = calcText(result.element as PsiMember, result.substitutor)
override fun getText(): String {
return text
}
private fun calcText(member: PsiMember, substitutor: PsiSubstitutor): String {
val aClass = member.containingClass ?: return ""
val p3cConfig = P3cConfig::class.java.getService()
return when (p3cConfig.locale) {
P3cConfig.localeZh -> String.format(P3cBundle.getMessage(fixKey),
HighlightUtil.formatClass(aClass, false),
HighlightUtil.formatClass(aClass), HighlightMessageUtil.getSymbolName(member, substitutor))
else -> String.format(P3cBundle.getMessage(fixKey), HighlightUtil.formatClass(aClass),
HighlightMessageUtil.getSymbolName(member, substitutor),
HighlightUtil.formatClass(aClass, false))
}
}
}
}
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JavaElementVisitor() {
override fun visitReferenceExpression(expression: PsiReferenceExpression) {
checkAccessStaticMemberViaInstanceReference(expression, holder, isOnTheFly)
}
}
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return HighlightDisplayLevels.BLOCKER
}
private fun checkAccessStaticMemberViaInstanceReference(expr: PsiReferenceExpression, holder: ProblemsHolder,
onTheFly: Boolean) {
val result = expr.advancedResolve(false)
val resolved = result.element as? PsiMember ?: return
val qualifierExpression = expr.qualifierExpression ?: return
if (qualifierExpression is PsiReferenceExpression) {
val qualifierResolved = qualifierExpression.resolve()
if (qualifierResolved is PsiClass || qualifierResolved is PsiPackage) {
return
}
}
if (!resolved.hasModifierProperty(PsiModifier.STATIC)) {
return
}
val description = String.format(P3cBundle.getMessage(
"$messageKey.errMsg"),
"${JavaHighlightUtil.formatType(qualifierExpression.type)}.${HighlightMessageUtil.getSymbolName(
resolved, result.substitutor)}")
if (!onTheFly) {
if (RemoveUnusedVariableUtil.checkSideEffects(qualifierExpression, null, ArrayList())) {
holder.registerProblem(expr, description)
return
}
}
holder.registerProblem(expr, description, createAccessStaticViaInstanceFix(expr, onTheFly, result))
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/standalone/AliDeprecationInspection.kt
================================================
/*
* 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.inspection.standalone
import com.alibaba.p3c.idea.config.P3cConfig
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.inspection.AliBaseInspection
import com.alibaba.p3c.idea.util.HighlightDisplayLevels
import com.alibaba.smartfox.idea.common.util.getService
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.codeInspection.deprecation.DeprecationInspection
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiReference
import org.jetbrains.annotations.Nls
import javax.swing.JComponent
/**
* @author caikang
* @date 2016/12/08
*/
class AliDeprecationInspection : DeprecationInspection, AliBaseInspection {
private val messageKey = "com.alibaba.p3c.idea.inspection.standalone.AliDeprecationInspection"
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
init {
IGNORE_INSIDE_DEPRECATED = true
IGNORE_ABSTRACT_DEPRECATED_OVERRIDES = false
IGNORE_IMPORT_STATEMENTS = false
IGNORE_METHODS_OF_DEPRECATED = false
}
override fun getDisplayName(): String {
return P3cBundle.getMessage("$messageKey.message")
}
override fun ruleName(): String {
return "AvoidUseDeprecationApiRule"
}
override fun getShortName(): String {
return "AliDeprecation"
}
override fun getStaticDescription(): String? {
return P3cBundle.getMessage("$messageKey.desc")
}
override fun createOptionsPanel(): JComponent? {
return null
}
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
val p3cConfig = P3cConfig::class.java.getService()
return when (p3cConfig.locale) {
P3cConfig.localeEn -> super.buildVisitor(holder, isOnTheFly)
else -> super.buildVisitor(DeprecationInspectionProblemsHolder(holder, isOnTheFly), isOnTheFly)
}
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return HighlightDisplayLevels.CRITICAL
}
class DeprecationInspectionProblemsHolder(private val holder: ProblemsHolder, onTheFly: Boolean) : ProblemsHolder(
holder.manager, holder.file, onTheFly) {
override fun registerProblem(psiElement: PsiElement,
@Nls descriptionTemplate: String,
fixes: Array?) {
holder.registerProblem(psiElement, getMessage(descriptionTemplate), *(fixes ?: emptyArray()))
}
override fun registerProblem(psiElement: PsiElement,
@Nls descriptionTemplate: String,
highlightType: ProblemHighlightType, fixes: Array?) {
holder.registerProblem(psiElement, getMessage(descriptionTemplate), highlightType, *(fixes ?: emptyArray()))
}
override fun registerProblem(reference: PsiReference, descriptionTemplate: String,
highlightType: ProblemHighlightType) {
holder.registerProblem(reference, getMessage(descriptionTemplate), highlightType)
}
override fun registerProblemForReference(reference: PsiReference,
highlightType: ProblemHighlightType, descriptionTemplate: String,
fixes: Array?) {
holder.registerProblemForReference(reference, highlightType, getMessage(descriptionTemplate),
*(fixes ?: emptyArray()))
}
override fun registerProblem(psiElement: PsiElement, rangeInElement: TextRange?,
message: String, fixes: Array?) {
holder.registerProblem(psiElement, rangeInElement, getMessage(message), *(fixes ?: emptyArray()))
}
override fun registerProblem(psiElement: PsiElement, message: String,
highlightType: ProblemHighlightType, rangeInElement: TextRange?,
fixes: Array?) {
holder.registerProblem(psiElement, getMessage(message), highlightType, rangeInElement,
*(fixes ?: emptyArray()))
}
private fun getMessage(msg: String): String {
return msg.replace("is deprecated", "已经过时了").replace("Default constructor in", "默认构造函数")
.replace("Overrides deprecated method in", "重写了过时的方法") + " #loc"
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/standalone/AliMissingOverrideAnnotationInspection.kt
================================================
/*
* 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.inspection.standalone
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.inspection.AliBaseInspection
import com.alibaba.p3c.idea.quickfix.DecorateInspectionGadgetsFix
import com.alibaba.p3c.idea.util.HighlightDisplayLevels
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.psi.CommonClassNames
import com.intellij.psi.PsiAnonymousClass
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiModifierListOwner
import com.intellij.psi.util.InheritanceUtil
import com.siyeh.ig.BaseInspectionVisitor
import com.siyeh.ig.InspectionGadgetsFix
import com.siyeh.ig.inheritance.MissingOverrideAnnotationInspection
import com.siyeh.ig.psiutils.MethodUtils
import javax.swing.JComponent
/**
* Batch QuickFix Supported
* @author caikang
* @date 2016/12/08
*/
class AliMissingOverrideAnnotationInspection : MissingOverrideAnnotationInspection, AliBaseInspection {
private val messageKey = "com.alibaba.p3c.idea.inspection.standalone.AliMissingOverrideAnnotationInspection"
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
init {
ignoreAnonymousClassMethods = false
ignoreObjectMethods = false
}
override fun getDisplayName(): String = P3cBundle.getMessage("$messageKey.message")
override fun getStaticDescription(): String? = P3cBundle.getMessage("$messageKey.desc")
override fun ruleName(): String = "MissingOverrideAnnotationRule"
override fun buildErrorString(vararg infos: Any): String = P3cBundle.getMessage("$messageKey.errMsg")
override fun createOptionsPanel(): JComponent? = null
override fun buildFix(vararg infos: Any): InspectionGadgetsFix? {
val fix = super.buildFix(*infos) ?: return null
return DecorateInspectionGadgetsFix(fix,
P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.standalone.AliMissingOverrideAnnotationInspection"))
}
override fun manualBuildFix(psiElement: PsiElement, isOnTheFly: Boolean): LocalQuickFix? = buildFix(psiElement)
override fun getDefaultLevel(): HighlightDisplayLevel = HighlightDisplayLevels.BLOCKER
override fun buildVisitor(): BaseInspectionVisitor = MissingOverrideAnnotationVisitor()
private inner class MissingOverrideAnnotationVisitor : BaseInspectionVisitor() {
override fun visitMethod(method: PsiMethod) {
if (method.nameIdentifier == null) {
return
}
if (method.isConstructor) {
return
}
if (method.hasModifierProperty(PsiModifier.PRIVATE) || method.hasModifierProperty(PsiModifier.STATIC)) {
return
}
val methodClass = method.containingClass ?: return
if (ignoreAnonymousClassMethods && methodClass is PsiAnonymousClass) {
return
}
if (hasOverrideAnnotation(method)) {
return
}
if (!isJdk6Override(method, methodClass) && !isJdk5Override(method, methodClass)) {
return
}
if (ignoreObjectMethods && (MethodUtils.isHashCode(method) ||
MethodUtils.isEquals(method) ||
MethodUtils.isToString(method))) {
return
}
registerMethodError(method)
}
private fun hasOverrideAnnotation(element: PsiModifierListOwner): Boolean {
val modifierList = element.modifierList
return modifierList?.findAnnotation(CommonClassNames.JAVA_LANG_OVERRIDE) != null
}
private fun isJdk6Override(method: PsiMethod, methodClass: PsiClass): Boolean {
val superMethods = method.findSuperMethods()
var hasSupers = false
for (superMethod in superMethods) {
val superClass = superMethod.containingClass
if (!InheritanceUtil.isInheritorOrSelf(methodClass, superClass, true)) {
continue
}
hasSupers = true
if (!superMethod.hasModifierProperty(PsiModifier.PROTECTED)) {
return true
}
}
// is override except if this is an interface method
// overriding a protected method in java.lang.Object
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6501053
return hasSupers && !methodClass.isInterface
}
private fun isJdk5Override(method: PsiMethod, methodClass: PsiClass): Boolean {
val superMethods = method.findSuperMethods()
for (superMethod in superMethods) {
val superClass = superMethod.containingClass
if (superClass == null || !InheritanceUtil.isInheritorOrSelf(methodClass, superClass, true)) {
continue
}
if (superClass.isInterface) {
continue
}
if (methodClass.isInterface && superMethod.hasModifierProperty(PsiModifier.PROTECTED)) {
// only true for J2SE java.lang.Object.clone(), but might
// be different on other/newer java platforms
continue
}
return true
}
return false
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/inspection/standalone/MapOrSetKeyShouldOverrideHashCodeEqualsInspection.kt
================================================
/*
* 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.inspection.standalone
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.alibaba.p3c.idea.inspection.AliBaseInspection
import com.alibaba.p3c.idea.util.HighlightDisplayLevels
import com.alibaba.p3c.idea.util.NumberConstants
import com.alibaba.p3c.idea.util.ObjectConstants
import com.google.common.collect.Sets
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.psi.CommonClassNames
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiType
import com.intellij.psi.PsiTypeParameter
import com.intellij.psi.PsiVariable
import com.siyeh.ig.BaseInspection
import com.siyeh.ig.BaseInspectionVisitor
import org.jetbrains.annotations.NonNls
/**
* @author caikang
* @date 2017/03/01
*/
class MapOrSetKeyShouldOverrideHashCodeEqualsInspection : BaseInspection, AliBaseInspection {
val messageKey = "com.alibaba.p3c.idea.inspection.standalone.MapOrSetKeyShouldOverrideHashCodeEqualsInspection"
constructor()
/**
* For Javassist
*/
constructor(any: Any?) : this()
override fun getDisplayName(): String {
return P3cBundle.getMessage("$messageKey.message")
}
override fun getStaticDescription(): String? {
return P3cBundle.getMessage("$messageKey.desc")
}
override fun buildErrorString(vararg infos: Any): String {
val type = infos[0] as PsiClassType
return String.format(P3cBundle.getMessage("$messageKey.errMsg"), type.className)
}
override fun buildVisitor(): BaseInspectionVisitor {
return MapOrSetKeyVisitor()
}
override fun ruleName(): String {
return "MapOrSetKeyShouldOverrideHashCodeEqualsRule"
}
override fun getDefaultLevel(): HighlightDisplayLevel {
return HighlightDisplayLevels.CRITICAL
}
internal enum class ClassType {
/**
* parameter type is Set
*/
SET,
MAP, OTHER;
override fun toString(): String {
val string = super.toString()
return string[0] + string.substring(1).toLowerCase()
}
}
private class MapOrSetKeyVisitor : BaseInspectionVisitor() {
private fun getClassType(aClass: PsiClass?): ClassType {
return isMapOrSet(aClass, Sets.newHashSet())
}
private fun isMapOrSet(aClass: PsiClass?, visitedClasses: MutableSet): ClassType {
if (aClass == null) {
return ClassType.OTHER
}
if (!visitedClasses.add(aClass)) {
return ClassType.OTHER
}
@NonNls
val className = aClass.qualifiedName
if (CommonClassNames.JAVA_UTIL_SET == className) {
return ClassType.SET
}
if (CommonClassNames.JAVA_UTIL_MAP == className) {
return ClassType.MAP
}
val supers = aClass.supers
return supers
.map { isMapOrSet(it, visitedClasses) }
.firstOrNull { it != ClassType.OTHER }
?: ClassType.OTHER
}
override fun visitVariable(variable: PsiVariable) {
super.visitVariable(variable)
val typeElement = variable.typeElement ?: return
val type = typeElement.type as? PsiClassType ?: return
val referenceElement = typeElement.innermostComponentReferenceElement ?: return
val aClass = type.resolve()
val collectionType = getClassType(aClass)
if (collectionType == ClassType.OTHER) {
return
}
val parameterList = referenceElement.parameterList
if (parameterList == null || parameterList.typeParameterElements.size == NumberConstants.INTEGER_SIZE_OR_LENGTH_0) {
return
}
val psiType = parameterList.typeArguments[0]
if (!redefineHashCodeEquals(psiType)) {
registerError(parameterList.typeParameterElements[0], psiType)
}
}
override fun visitMethodCallExpression(expression: PsiMethodCallExpression) {
val methodExpression = expression.methodExpression
val qualifierExpression = methodExpression.qualifierExpression ?: return
val type = qualifierExpression.type as? PsiClassType ?: return
val aClass = type.resolve()
val collectionType = getClassType(aClass)
if (collectionType == ClassType.OTHER) {
return
}
@NonNls
val methodName = methodExpression.referenceName
if (collectionType == ClassType.SET && ObjectConstants.METHOD_NAME_ADD != methodName) {
return
}
if (collectionType == ClassType.MAP && ObjectConstants.METHOD_NAME_PUT != methodName) {
return
}
val argumentList = expression.argumentList
val arguments = argumentList.expressions
if (collectionType == ClassType.SET && arguments.size != NumberConstants.INTEGER_SIZE_OR_LENGTH_1) {
return
}
if (collectionType == ClassType.MAP && arguments.size != NumberConstants.INTEGER_SIZE_OR_LENGTH_2) {
return
}
val argument = arguments[0]
val argumentType = argument.type
if (argumentType == null || redefineHashCodeEquals(argumentType)) {
return
}
registerMethodCallError(expression, argumentType)
}
}
companion object {
private val skipJdkPackageJava = "java."
private val skipJdkPackageJavax = "javax."
private fun redefineHashCodeEquals(psiType: PsiType): Boolean {
if (psiType !is PsiClassType) {
return true
}
val psiClass = psiType.resolve() ?: return false
val skip = psiClass.containingFile == null || psiClass is PsiTypeParameter
|| psiClass.isEnum || psiClass.isInterface
|| psiClass.containingFile.fileType !is JavaFileType
|| psiClass.qualifiedName?.startsWith(skipJdkPackageJava) ?: false
|| psiClass.qualifiedName?.startsWith(skipJdkPackageJavax) ?: false
if (skip) {
return true
}
val hashCodeMethods = psiClass.findMethodsByName(ObjectConstants.METHOD_NAME_HASHCODE, false)
if (hashCodeMethods.size == NumberConstants.INTEGER_SIZE_OR_LENGTH_0) {
return false
}
val equalsMethods = psiClass.findMethodsByName(ObjectConstants.METHOD_NAME_EQUALS, false)
return equalsMethods.size > NumberConstants.INTEGER_SIZE_OR_LENGTH_0
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/pmd/AliPmdProcessor.kt
================================================
/*
* 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.pmd
import com.alibaba.p3c.idea.component.AliProjectComponent
import com.google.common.base.Throwables
import com.intellij.openapi.application.ex.ApplicationUtil
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.psi.PsiFile
import net.sourceforge.pmd.PMDConfiguration
import net.sourceforge.pmd.PMDException
import net.sourceforge.pmd.Report
import net.sourceforge.pmd.Rule
import net.sourceforge.pmd.RuleContext
import net.sourceforge.pmd.RuleSetFactory
import net.sourceforge.pmd.RuleSets
import net.sourceforge.pmd.RuleViolation
import net.sourceforge.pmd.RulesetsFactoryUtils
import net.sourceforge.pmd.util.ResourceLoader
import java.io.IOException
import java.io.StringReader
import net.sourceforge.pmd.SourceCodeProcessor as PmdSourceCodeProcessor
/**
* @author caikang
* @date 2016/12/11
*/
class AliPmdProcessor private constructor(val rule: Rule? = null, val ruleSets: RuleSets? = null) {
constructor(rule: Rule) : this(rule, null)
constructor(ruleSets: RuleSets) : this(null, ruleSets)
private val ruleSetFactory: RuleSetFactory
private val configuration = PMDConfiguration()
init {
ruleSetFactory = RulesetsFactoryUtils.getRulesetFactory(configuration, ResourceLoader())
}
fun processFile(psiFile: PsiFile, isOnTheFly: Boolean): List {
configuration.setSourceEncoding(psiFile.virtualFile.charset.name())
configuration.inputPaths = psiFile.virtualFile.canonicalPath
val document = FileDocumentManager.getInstance().getDocument(psiFile.virtualFile) ?: return emptyList()
val project = psiFile.project
val aliProjectComponent = project.getComponent(AliProjectComponent::class.java)
val fileContext = aliProjectComponent.getFileContext(psiFile.virtualFile) ?: return emptyList()
val ctx = RuleContext()
val niceFileName = psiFile.virtualFile.canonicalPath!!
val report = Report.createReport(ctx, niceFileName)
val processRuleSets = ruleSets ?: RuleSets().also { rs ->
val ruleSet = ruleSetFactory.createSingleRuleRuleSet(rule)
rs.addRuleSet(ruleSet)
}
LOG.debug("Processing " + ctx.sourceCodeFilename)
try {
val reader = StringReader(document.text)
ctx.languageVersion = null
if (isOnTheFly) {
SourceCodeProcessor(configuration, document, fileContext, isOnTheFly).processSourceCode(
reader,
processRuleSets,
ctx
)
} else {
PmdSourceCodeProcessor(configuration).processSourceCode(reader, processRuleSets, 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 (pce: ProcessCanceledException) {
throw pce
} catch (re: RuntimeException) {
val root = Throwables.getRootCause(re)
if (root !is ApplicationUtil.CannotRunReadActionException) {
LOG.error("RuntimeException while processing file: $niceFileName", re)
}
}
return ctx.report.toList()
}
companion object {
private val LOG = Logger.getInstance(AliPmdProcessor::class.java)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/pmd/SourceCodeProcessor.kt
================================================
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package com.alibaba.p3c.idea.pmd
import com.alibaba.p3c.idea.component.AliProjectComponent.FileContext
import com.alibaba.p3c.idea.config.P3cConfig
import com.alibaba.p3c.idea.util.withLockNotInline
import com.alibaba.p3c.idea.util.withTryLock
import com.google.common.cache.Cache
import com.google.common.cache.CacheBuilder
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Document
import net.sourceforge.pmd.PMD
import net.sourceforge.pmd.PMDConfiguration
import net.sourceforge.pmd.PMDException
import net.sourceforge.pmd.RuleContext
import net.sourceforge.pmd.RuleSets
import net.sourceforge.pmd.benchmark.TimeTracker
import net.sourceforge.pmd.benchmark.TimedOperationCategory
import net.sourceforge.pmd.lang.Language
import net.sourceforge.pmd.lang.LanguageVersion
import net.sourceforge.pmd.lang.LanguageVersionHandler
import net.sourceforge.pmd.lang.Parser
import net.sourceforge.pmd.lang.ast.Node
import net.sourceforge.pmd.lang.ast.ParseException
import java.io.Reader
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.MILLISECONDS
class SourceCodeProcessor(
private val configuration: PMDConfiguration,
private val document: Document,
private val fileContext: FileContext,
private val isOnTheFly: Boolean
) {
/**
* Processes the input stream against a rule set using the given input
* encoding. If the LanguageVersion is `null` on the RuleContext,
* it will be automatically determined. Any code which wishes to process
* files for different Languages, will need to be sure to either properly
* set the Language on the RuleContext, or set it to `null`
* first.
*
* @see RuleContext.setLanguageVersion
* @see PMDConfiguration.getLanguageVersionOfFile
* @param sourceCode
* The Reader to analyze.
* @param ruleSets
* The collection of rules to process against the file.
* @param ctx
* The context in which PMD is operating.
* @throws PMDException
* if the input encoding is unsupported, the input stream could
* not be parsed, or other error is encountered.
*/
@Throws(PMDException::class)
fun processSourceCode(sourceCode: Reader, ruleSets: RuleSets, ctx: RuleContext) {
determineLanguage(ctx)
try {
ruleSets.start(ctx)
processSource(sourceCode, ruleSets, ctx)
} catch (pe: ParseException) {
configuration.analysisCache.analysisFailed(ctx.sourceCodeFile)
throw PMDException("Error while parsing " + ctx.sourceCodeFilename, pe)
} catch (e: Exception) {
configuration.analysisCache.analysisFailed(ctx.sourceCodeFile)
throw PMDException("Error while processing " + ctx.sourceCodeFilename, e)
} finally {
ruleSets.end(ctx)
}
}
private fun parse(ctx: RuleContext, sourceCode: Reader, parser: Parser): Node {
TimeTracker.startOperation(TimedOperationCategory.PARSER).use {
val rootNode = parser.parse(ctx.sourceCodeFilename, sourceCode)
ctx.report.suppress(parser.suppressMap)
return rootNode
}
}
private fun getRootNode(sourceCode: Reader, ruleSets: RuleSets, ctx: RuleContext): Node? {
if (!smartFoxConfig.astCacheEnable) {
return parseNode(ctx, ruleSets, sourceCode)
}
val node = getNode(ctx.sourceCodeFilename, isOnTheFly)
if (node != null) {
return node
}
if (document.lineCount > 3000 && isOnTheFly) {
return null
}
val lock = fileContext.lock
val readLock = lock.readLock()
val writeLock = lock.writeLock()
val ruleName = ruleSets.allRules.joinToString(",") { it.name }
val fileName = ctx.sourceCodeFilename
val readAction = {
getNode(ctx.sourceCodeFilename, isOnTheFly)
}
val cacheNode = if (isOnTheFly) {
readLock.withTryLock(50, MILLISECONDS, readAction)
} else {
val start = System.currentTimeMillis()
LOG.info("rule:$ruleName,file:$fileName require read lock")
readLock.withLockNotInline(readAction).also {
LOG.info("rule:$ruleName,file:$fileName get result $it with read lock ,elapsed ${System.currentTimeMillis() - start}")
}
}
if (cacheNode != null) {
return cacheNode
}
val writeAction = {
val finalNode = getNode(ctx.sourceCodeFilename, isOnTheFly)
if (finalNode == null) {
val start = System.currentTimeMillis()
if (!isOnTheFly) {
LOG.info("rule:$ruleName,file:$fileName parse with write lock")
}
parseNode(ctx, ruleSets, sourceCode).also {
if (!isOnTheFly) {
LOG.info("rule:$ruleName,file:$fileName get result $it parse with write lock ,elapsed ${System.currentTimeMillis() - start}")
}
}
} else {
finalNode
}
}
return if (isOnTheFly) {
writeLock.withTryLock(50, MILLISECONDS, writeAction)!!
} else {
writeLock.withLockNotInline(
writeAction
)!!
}
}
private fun parseNode(ctx: RuleContext, ruleSets: RuleSets, sourceCode: Reader): Node {
val languageVersion = ctx.languageVersion
val languageVersionHandler = languageVersion.languageVersionHandler
val parser = PMD.parserFor(languageVersion, configuration)
val rootNode = parse(ctx, sourceCode, parser)
symbolFacade(rootNode, languageVersionHandler)
val language = languageVersion.language
usesDFA(languageVersion, rootNode, ruleSets, language)
usesTypeResolution(languageVersion, rootNode, ruleSets, language)
onlyTheFlyCache.put(ctx.sourceCodeFilename, rootNode)
userTriggerNodeCache.put(ctx.sourceCodeFilename, rootNode)
return rootNode
}
private fun symbolFacade(rootNode: Node, languageVersionHandler: LanguageVersionHandler) {
TimeTracker.startOperation(TimedOperationCategory.SYMBOL_TABLE)
.use { languageVersionHandler.getSymbolFacade(configuration.classLoader).start(rootNode) }
}
private fun resolveQualifiedNames(rootNode: Node, handler: LanguageVersionHandler) {
TimeTracker.startOperation(TimedOperationCategory.QUALIFIED_NAME_RESOLUTION)
.use { handler.getQualifiedNameResolutionFacade(configuration.classLoader).start(rootNode) }
}
// private ParserOptions getParserOptions(final LanguageVersionHandler
// languageVersionHandler) {
// // TODO Handle Rules having different parser options.
// ParserOptions parserOptions =
// languageVersionHandler.getDefaultParserOptions();
// parserOptions.setSuppressMarker(configuration.getSuppressMarker());
// return parserOptions;
// }
private fun usesDFA(languageVersion: LanguageVersion, rootNode: Node, ruleSets: RuleSets, language: Language) {
if (ruleSets.usesDFA(language)) {
TimeTracker.startOperation(TimedOperationCategory.DFA).use { to ->
val dataFlowFacade = languageVersion.languageVersionHandler.dataFlowFacade
dataFlowFacade.start(rootNode)
}
}
}
private fun usesTypeResolution(
languageVersion: LanguageVersion, rootNode: Node, ruleSets: RuleSets,
language: Language
) {
if (ruleSets.usesTypeResolution(language)) {
TimeTracker.startOperation(TimedOperationCategory.TYPE_RESOLUTION).use { to ->
languageVersion.languageVersionHandler.getTypeResolutionFacade(configuration.classLoader)
.start(rootNode)
}
}
}
private fun usesMultifile(
rootNode: Node, languageVersionHandler: LanguageVersionHandler, ruleSets: RuleSets,
language: Language
) {
if (ruleSets.usesMultifile(language)) {
TimeTracker.startOperation(TimedOperationCategory.MULTIFILE_ANALYSIS)
.use { languageVersionHandler.multifileFacade.start(rootNode) }
}
}
private fun processSource(sourceCode: Reader, ruleSets: RuleSets, ctx: RuleContext) {
val languageVersion = ctx.languageVersion
val languageVersionHandler = languageVersion.languageVersionHandler
val rootNode = getRootNode(sourceCode, ruleSets, ctx) ?: return
resolveQualifiedNames(rootNode, languageVersionHandler)
symbolFacade(rootNode, languageVersionHandler)
val language = languageVersion.language
usesDFA(languageVersion, rootNode, ruleSets, language)
usesTypeResolution(languageVersion, rootNode, ruleSets, language)
usesMultifile(rootNode, languageVersionHandler, ruleSets, language)
val acus = listOf(rootNode)
ruleSets.apply(acus, ctx, language)
}
private fun determineLanguage(ctx: RuleContext) {
// If LanguageVersion of the source file is not known, make a
// determination
if (ctx.languageVersion == null) {
val languageVersion = configuration.getLanguageVersionOfFile(ctx.sourceCodeFilename)
ctx.languageVersion = languageVersion
}
}
companion object {
val smartFoxConfig = ServiceManager.getService(P3cConfig::class.java)!!
private lateinit var onlyTheFlyCache: Cache
private lateinit var userTriggerNodeCache: Cache
private val LOG = Logger.getInstance(SourceCodeProcessor::class.java)
init {
reInitNodeCache(smartFoxConfig.astCacheTime)
}
fun reInitNodeCache(expireTime: Long) {
onlyTheFlyCache = CacheBuilder.newBuilder().concurrencyLevel(16)
.expireAfterWrite(expireTime, TimeUnit.MILLISECONDS)
.maximumSize(300)
.build()!!
userTriggerNodeCache = CacheBuilder.newBuilder().concurrencyLevel(16)
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(300)
.build()!!
}
fun invalidateCache(file: String) {
onlyTheFlyCache.invalidate(file)
userTriggerNodeCache.invalidate(file)
}
fun invalidUserTrigger(file: String) {
userTriggerNodeCache.invalidate(file)
}
fun invalidateAll() {
onlyTheFlyCache.invalidateAll()
userTriggerNodeCache.invalidateAll()
}
fun getNode(file: String, isOnTheFly: Boolean): Node? {
return if (isOnTheFly) onlyTheFlyCache.getIfPresent(file) else userTriggerNodeCache.getIfPresent(file)
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/pmd/index/InspectionDataSource.kt
================================================
/*
* 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.pmd.index
import com.intellij.util.indexing.FileContent
import net.sourceforge.pmd.util.datasource.DataSource
import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.InputStream
/**
* @author caikang
* @date 2016/12/11
*/
class InspectionDataSource(private val fileContent: FileContent) : DataSource {
@Throws(IOException::class)
override fun getInputStream(): InputStream {
return ByteArrayInputStream(fileContent.content)
}
override fun getNiceFileName(shortNames: Boolean, inputFileName: String?): String {
return fileContent.fileName
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/pmd/index/InspectionRenderer.kt
================================================
/*
* 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.pmd.index
import net.sourceforge.pmd.Report
import net.sourceforge.pmd.RuleViolation
import net.sourceforge.pmd.renderers.AbstractRenderer
import net.sourceforge.pmd.renderers.Renderer
import net.sourceforge.pmd.util.datasource.DataSource
import java.io.IOException
/**
* @author caikang
* @date 2016/12/11
*/
class InspectionRenderer : AbstractRenderer("InspectionRenderer", "Idea Inspection for pmd result"), Renderer {
private lateinit var ruleProblems: List
override fun defaultFileExtension(): String? {
return null
}
@Throws(IOException::class)
override fun start() {
}
override fun startFileAnalysis(dataSource: DataSource) {
}
@Throws(IOException::class)
override fun renderFileReport(report: Report) {
ruleProblems = report.map { it }
}
@Throws(IOException::class)
override fun end() {
}
fun getViolations(): List {
return ruleProblems
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/AliQuickFix.kt
================================================
/*
* 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.quickfix
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiIdentifier
import com.intellij.psi.PsiLocalVariable
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiParameter
/**
*
*
* @author caikang
* @date 2017/02/27
*/
interface AliQuickFix : LocalQuickFix {
val ruleName: String
val onlyOnThFly: Boolean
override fun getFamilyName(): String {
return groupName
}
companion object {
const val groupName = "Ali QuickFix"
fun doQuickFix(newIdentifier: String, project: Project, psiIdentifier: PsiIdentifier) {
val offset = psiIdentifier.textOffset
val cannotFix = psiIdentifier.parent !is PsiMember
&& !(psiIdentifier.parent is PsiLocalVariable || psiIdentifier.parent is PsiParameter)
if (cannotFix) {
return
}
val editor = FileEditorManager.getInstance(project).selectedTextEditor ?: return
editor.caretModel.moveToOffset(psiIdentifier.textOffset)
val anAction = ActionManager.getInstance().getAction("RenameElement")
val psiFile = psiIdentifier.containingFile
commitDocumentIfNeeded(psiFile, project)
val event = AnActionEvent.createFromDataContext("MainMenu", anAction.templatePresentation) {
when (it) {
CommonDataKeys.PROJECT.name -> project
CommonDataKeys.EDITOR.name -> editor
CommonDataKeys.PSI_FILE.name -> psiFile
CommonDataKeys.PSI_ELEMENT.name -> psiIdentifier.parent
else -> null
}
}
val psiFacade = JavaPsiFacade.getInstance(project)
val factory = psiFacade.elementFactory
anAction.actionPerformed(event)
// origin PsiIdentifier is unavailable
psiFile.findElementAt(offset)?.replace(factory.createIdentifier(newIdentifier))
}
private fun commitDocumentIfNeeded(file: PsiFile?, project: Project) {
if (file == null) {
return
}
val manager = PsiDocumentManager.getInstance(project)
val cachedDocument = manager.getCachedDocument(file) ?: return
manager.commitDocument(cachedDocument)
}
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/AvoidStartWithDollarAndUnderLineNamingQuickFix.kt
================================================
/*
* 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.quickfix
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiIdentifier
import org.apache.commons.lang3.StringUtils
/**
*
*
* @author caikang
* @date 2017/02/28
*/
object AvoidStartWithDollarAndUnderLineNamingQuickFix : AliQuickFix {
override val ruleName: String
get() = "AvoidStartWithDollarAndUnderLineNamingRule"
override val onlyOnThFly: Boolean
get() = true
override fun getName(): String {
return P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.delete_$")
}
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val psiIdentifier = descriptor.psiElement as? PsiIdentifier ?: return
val identifier = psiIdentifier.text
val resultName = StringUtils.replacePattern(identifier, "^[\$_]+", "")
if (resultName.toLongOrNull() != null) {
return
}
AliQuickFix.doQuickFix(resultName, project, psiIdentifier)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/ClassMustHaveAuthorQuickFix.kt
================================================
/*
* 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.quickfix
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.javadoc.PsiDocToken
import com.siyeh.ig.InspectionGadgetsFix
/**
*
*
* @author caikang
* @date 2017/02/27
*/
object ClassMustHaveAuthorQuickFix : InspectionGadgetsFix(), AliQuickFix {
val tag = "@author ${System.getProperty("user.name") ?: System.getenv("USER")}"
override fun doFix(project: Project?, descriptor: ProblemDescriptor?) {
descriptor ?: return
val psiClass = descriptor.psiElement as? PsiClass ?: descriptor.psiElement?.parent as? PsiClass ?: return
val document = psiClass.docComment
val psiFacade = JavaPsiFacade.getInstance(project)
val factory = psiFacade.elementFactory
if (document == null) {
val doc = factory.createDocCommentFromText("""
/**
* $tag
*/
""")
if (psiClass.isEnum) {
psiClass.containingFile.addAfter(doc, psiClass.prevSibling)
} else {
psiClass.addBefore(doc, psiClass.firstChild)
}
return
}
val regex = Regex("Created by (.*) on (.*)\\.")
for (line in document.descriptionElements) {
if (line is PsiDocToken && line.text.contains(regex)) {
val groups = regex.find(line.text)?.groups ?: continue
val author = groups[1]?.value ?: continue
val date = groups[2]?.value ?: continue
document.addBefore(factory.createDocTagFromText("@date $date"), line)
document.addBefore(factory.createDocTagFromText("@author $author"), line)
line.delete()
return
}
}
if (document.tags.isNotEmpty()) {
document.addBefore(factory.createDocTagFromText(tag), document.tags[0])
return
}
document.add(factory.createDocTagFromText(tag))
}
override val ruleName: String
get() = "ClassMustHaveAuthorRule"
override val onlyOnThFly: Boolean
get() = true
override fun getName(): String {
return P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.generate.author")
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/ConstantFieldShouldBeUpperCaseQuickFix.kt
================================================
/*
* 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.quickfix
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.google.common.base.Splitter
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiIdentifier
/**
*
*
* @author caikang
* @date 2017/02/28
*/
object ConstantFieldShouldBeUpperCaseQuickFix : AliQuickFix {
val separator = '_'
override fun getName(): String {
return P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.field.to.upperCaseWithUnderscore")
}
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val psiIdentifier = descriptor.psiElement as? PsiIdentifier ?: return
val identifier = psiIdentifier.text
val list = Splitter.on(separator).trimResults().omitEmptyStrings().splitToList(identifier)
val resultName = list.joinToString(separator.toString()) {
separateCamelCase(it).toUpperCase()
}
AliQuickFix.doQuickFix(resultName, project, psiIdentifier)
}
private fun separateCamelCase(name: String): String {
val translation = StringBuilder()
for (i in 0 until name.length - 1) {
val character = name[i]
val next = name[i + 1]
if (Character.isUpperCase(character) && !next.isUpperCase() && translation.isNotEmpty()) {
translation.append(separator)
}
if (character != separator) {
translation.append(character)
}
}
val last = name.last()
if (last != separator) {
translation.append(last)
}
return translation.toString()
}
override val ruleName: String
get() = "ConstantFieldShouldBeUpperCaseRule"
override val onlyOnThFly: Boolean
get() = true
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/DecorateInspectionFix.kt
================================================
/*
* 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.quickfix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.siyeh.ig.InspectionGadgetsFix
/**
*
*
* @author caikang
* @date 2017/03/02
*/
class DecorateInspectionGadgetsFix(val fix: InspectionGadgetsFix,
internal val name: String,
internal val familyName: String = name) : InspectionGadgetsFix() {
override fun getName(): String {
return name
}
override fun doFix(project: Project, descriptor: ProblemDescriptor) {
fix.applyFix(project, descriptor)
}
override fun getFamilyName(): String {
return familyName
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/LowerCamelCaseVariableNamingQuickFix.kt
================================================
/*
* 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.quickfix
import com.alibaba.p3c.idea.i18n.P3cBundle
import com.google.common.base.Splitter
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiIdentifier
/**
*
*
* @author caikang
* @date 2017/02/28
*/
object LowerCamelCaseVariableNamingQuickFix : AliQuickFix {
override val ruleName: String
get() = "LowerCamelCaseVariableNamingRule"
override val onlyOnThFly: Boolean
get() = true
override fun getName(): String {
return P3cBundle.getMessage("com.alibaba.p3c.idea.quickfix.variable.lowerCamelCase")
}
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val psiIdentifier = descriptor.psiElement as? PsiIdentifier ?: return
val identifier = psiIdentifier.text
val resultName = toLowerCamelCase(identifier)
AliQuickFix.doQuickFix(resultName, project, psiIdentifier)
}
private fun toLowerCamelCase(identifier: String): String {
val list = Splitter.onPattern("[^a-z0-9A-Z]+").trimResults()
.omitEmptyStrings().split(identifier).toList()
val result = list.mapIndexed { i, s ->
val charArray = s.toCharArray()
charArray[0] = if (i == 0) charArray[0].toLowerCase() else charArray[0].toUpperCase()
String(charArray)
}
return result.joinToString("")
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/quickfix/VmQuietReferenceQuickFix.kt
================================================
/*
* 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.quickfix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.project.Project
/**
*
*
* @author caikang
* @date 2017/01/26
*/
object VmQuietReferenceQuickFix : AliQuickFix {
override val onlyOnThFly: Boolean
get() = true
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val textRange = descriptor.textRangeInElement ?: return
val document = FileDocumentManager.getInstance().getDocument(
descriptor.startElement.containingFile.virtualFile) ?: return
document.insertString(textRange.startOffset + 1, "!")
}
override val ruleName = "UseQuietReferenceNotationRule"
override fun getName(): String {
return "为变量添加!"
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/DocumentUtils.kt
================================================
/*
* 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.util
import com.intellij.openapi.editor.Document
import com.intellij.openapi.util.TextRange
/**
*
*
* @author caikang
* @date 2017/03/16
6
*/
object DocumentUtils {
private val PMD_TAB_SIZE = 8
fun calculateRealOffset(document: Document, line: Int, pmdColumn: Int): Int {
val maxLine = document.lineCount
if (maxLine < line) {
return -1
}
val lineOffset = document.getLineStartOffset(line - 1)
return lineOffset + calculateRealColumn(document, line, pmdColumn)
}
fun calculateLineStart(document: Document, line: Int): Int {
val maxLine = document.lineCount
if (maxLine < line) {
return -1
}
return document.getLineStartOffset(line - 1)
}
fun calculateRealColumn(document: Document, line: Int, pmdColumn: Int): Int {
var realColumn = pmdColumn - 1
val minusSize = PMD_TAB_SIZE - 1
val docLine = line - 1
val lineStartOffset = document.getLineStartOffset(docLine)
val lineEndOffset = document.getLineEndOffset(docLine)
val text = document.getText(TextRange(lineStartOffset, lineEndOffset))
text.forEachIndexed { i, c ->
if (c == '\t') {
realColumn -= minusSize
}
if (i >= realColumn) {
return@forEachIndexed
}
}
return realColumn
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/HighlightDisplayLevels.kt
================================================
/*
* 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.util
import com.intellij.codeHighlighting.HighlightDisplayLevel
/**
*
*
* @author caikang
* @date 2017/02/04
*/
object HighlightDisplayLevels {
val BLOCKER = HighlightDisplayLevel(HighlightSeverities.BLOCKER, HighlightDisplayLevel.ERROR.icon)
val CRITICAL = HighlightDisplayLevel(HighlightSeverities.CRITICAL, HighlightDisplayLevel.WARNING.icon)
val MAJOR = HighlightDisplayLevel(HighlightSeverities.MAJOR, HighlightDisplayLevel.WEAK_WARNING.icon)
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/HighlightInfoTypes.kt
================================================
/*
* 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.util
import com.intellij.codeInsight.daemon.impl.HighlightInfoType
import com.intellij.openapi.editor.colors.CodeInsightColors
/**
*
*
* @author caikang
* @date 2017/02/04
*/
object HighlightInfoTypes {
val BLOCKER: HighlightInfoType = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverities.BLOCKER,
CodeInsightColors.ERRORS_ATTRIBUTES)
val CRITICAL: HighlightInfoType = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverities.CRITICAL,
CodeInsightColors.WARNINGS_ATTRIBUTES)
val MAJOR: HighlightInfoType = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverities.MAJOR,
CodeInsightColors.WEAK_WARNING_ATTRIBUTES)
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/HighlightSeverities.kt
================================================
/*
* 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.util
import com.intellij.lang.annotation.HighlightSeverity
/**
*
*
* @author caikang
* @date 2017/02/04
*/
object HighlightSeverities {
val MAJOR = HighlightSeverity("MAJOR", 397)
/**
* The standard severity level for warning annotations.
*/
val CRITICAL = HighlightSeverity("CRITICAL", 398)
/**
* The standard severity level for error annotations.
*/
val BLOCKER = HighlightSeverity("BLOCKER", 399)
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/NumberConstants.kt
================================================
/*
* 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.util
/**
* @author caikang
* @date 2016/12/28
*/
object NumberConstants {
val INTEGER_SIZE_OR_LENGTH_0 = 0
val INTEGER_SIZE_OR_LENGTH_1 = 1
val INTEGER_SIZE_OR_LENGTH_2 = 2
val INDEX_0 = 0
val INDEX_1 = 1
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/ObjectConstants.kt
================================================
/*
* 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.util
/**
* @author caikang
* @date 2016/12/28
*/
object ObjectConstants {
val METHOD_NAME_EQUALS = "equals"
val METHOD_NAME_HASHCODE = "hashCode"
val METHOD_NAME_ADD = "add"
val METHOD_NAME_PUT = "put"
val CLASS_LITERAL = "class"
val INTERFACE_LITERAL = "interface"
val ENUM_LITERAL = "enum"
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/ProblemsUtils.kt
================================================
/*
* 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.util
import com.alibaba.p3c.pmd.lang.java.rule.comment.AvoidCommentBehindStatementRule
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiIdentifier
import com.intellij.psi.PsiJavaToken
import com.intellij.psi.PsiKeyword
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.impl.source.tree.ElementType
/**
*
*
* @author caikang
* @date 2017/03/16
6
*/
object ProblemsUtils {
private val highlightLineRules = setOf(AvoidCommentBehindStatementRule::class.java.simpleName)
fun createProblemDescriptorForPmdRule(psiFile: PsiFile, manager: InspectionManager, isOnTheFly: Boolean,
ruleName: String, desc: String, start: Int, end: Int,
checkLine: Int = 0,
quickFix: (PsiElement) -> LocalQuickFix? = {
QuickFixes.getQuickFix(ruleName, isOnTheFly)
}): ProblemDescriptor? {
val document = FileDocumentManager.getInstance().getDocument(psiFile.virtualFile) ?: return null
if (highlightLineRules.contains(ruleName) && checkLine <= document.lineCount) {
val lineNumber = if (start >= document.textLength) {
document.lineCount - 1
} else {
document.getLineNumber(start)
}
val textRange = TextRange(document.getLineStartOffset(lineNumber), document.getLineEndOffset(lineNumber))
return createTextRangeProblem(manager, textRange, isOnTheFly, psiFile, ruleName, desc)
}
if (psiFile.virtualFile.canonicalPath!!.endsWith(".vm")) {
return createTextRangeProblem(manager, TextRange(start, end), isOnTheFly, psiFile, ruleName, desc)
}
var psiElement = psiFile.findElementAt(start) ?: return null
psiElement = transform(psiElement) ?: return null
var endElement = if (start == end) psiElement else getEndElement(psiFile, psiElement, end)
if (psiElement != endElement && endElement.parent is PsiField) {
psiElement = endElement
}
if (endElement is PsiWhiteSpace) {
endElement = psiElement
}
if (psiElement is PsiWhiteSpace) {
val textRange = TextRange(start, end)
return createTextRangeProblem(manager, textRange, isOnTheFly, psiFile, ruleName, desc)
}
if (psiElement.textRange.startOffset >= endElement.textRange.endOffset) {
if (!(psiElement is PsiFile && endElement is PsiFile)) {
return null
}
endElement = psiElement
}
return manager.createProblemDescriptor(psiElement, endElement,
desc, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly,
quickFix(psiElement))
}
private fun getEndElement(psiFile: PsiFile, psiElement: PsiElement, endOffset: Int): PsiElement {
var endElement = psiFile.findElementAt(endOffset)
if (endElement is PsiJavaToken && endElement.tokenType === ElementType.SEMICOLON) {
endElement = psiFile.findElementAt(endOffset - 1)
}
if (endElement is PsiIdentifier) {
return endElement
}
if (psiElement is PsiIdentifier) {
return psiElement
}
if (endElement == null || endElement is PsiWhiteSpace
|| psiElement.textRange.startOffset >= endElement.textRange.endOffset) {
endElement = psiElement
}
return endElement
}
private fun transform(element: PsiElement): PsiElement? {
var psiElement: PsiElement? = element
while (psiElement is PsiWhiteSpace) {
psiElement = psiElement.getNextSibling()
}
if (psiElement == null) {
return null
}
if (psiElement is PsiKeyword && psiElement.text != null && (ObjectConstants.CLASS_LITERAL == psiElement.text
|| ObjectConstants.INTERFACE_LITERAL == psiElement.text
|| ObjectConstants.ENUM_LITERAL == psiElement.text) && psiElement.parent is PsiClass) {
val parent = psiElement.parent as PsiClass
val identifier = parent.nameIdentifier
return identifier ?: psiElement
}
return psiElement
}
private fun createTextRangeProblem(manager: InspectionManager, textRange: TextRange, isOnTheFly: Boolean,
psiFile: PsiFile, ruleName: String, desc: String,
quickFix: () -> LocalQuickFix? = {
QuickFixes.getQuickFix(ruleName, isOnTheFly)
}): ProblemDescriptor {
return manager.createProblemDescriptor(psiFile, textRange,
desc, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
isOnTheFly, quickFix())
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/QuickFixes.kt
================================================
/*
* 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.util
import com.alibaba.p3c.idea.quickfix.AvoidStartWithDollarAndUnderLineNamingQuickFix
import com.alibaba.p3c.idea.quickfix.ClassMustHaveAuthorQuickFix
import com.alibaba.p3c.idea.quickfix.ConstantFieldShouldBeUpperCaseQuickFix
import com.alibaba.p3c.idea.quickfix.LowerCamelCaseVariableNamingQuickFix
import com.alibaba.p3c.idea.quickfix.VmQuietReferenceQuickFix
import com.intellij.codeInspection.LocalQuickFix
/**
*
*
* @author caikang
* @date 2017/02/06
*/
object QuickFixes {
val quickFixes = mutableMapOf(VmQuietReferenceQuickFix.ruleName to VmQuietReferenceQuickFix,
ClassMustHaveAuthorQuickFix.ruleName to ClassMustHaveAuthorQuickFix,
ConstantFieldShouldBeUpperCaseQuickFix.ruleName to ConstantFieldShouldBeUpperCaseQuickFix,
AvoidStartWithDollarAndUnderLineNamingQuickFix.ruleName to AvoidStartWithDollarAndUnderLineNamingQuickFix,
LowerCamelCaseVariableNamingQuickFix.ruleName to LowerCamelCaseVariableNamingQuickFix)
fun getQuickFix(rule: String, isOnTheFly: Boolean): LocalQuickFix? {
val quickFix = quickFixes[rule] ?: return null
if (!quickFix.onlyOnThFly) {
return quickFix
}
if (!isOnTheFly && quickFix.onlyOnThFly) {
return null
}
return quickFix
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/util/withLockNotInline.kt
================================================
package com.alibaba.p3c.idea.util
import com.intellij.openapi.progress.ProcessCanceledException
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.Lock
/**
* @date 2020/06/14
* @author caikang
*/
fun Lock.withLockNotInline(action: () -> T?): T? {
lock()
try {
return action()
} finally {
unlock()
}
}
fun Semaphore.withAcquire(action: () -> T?): T? {
acquire()
try {
return action()
} finally {
release()
}
}
fun Lock.withTryLock(time: Long, timeUnit: TimeUnit, action: () -> T?): T? {
if (!tryLock(time, timeUnit)) {
throw ProcessCanceledException()
}
try {
return action()
} finally {
unlock()
}
}
fun Semaphore.withTryAcquire(time: Long, timeUnit: TimeUnit, action: () -> T?): T? {
if (!tryAcquire(time, timeUnit)) {
throw ProcessCanceledException()
}
try {
return action()
} finally {
release()
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/vcs/AliCodeAnalysisCheckinHandler.kt
================================================
/*
* 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.vcs
import com.alibaba.p3c.idea.action.AliInspectionAction
import com.alibaba.p3c.idea.compatible.inspection.Inspections
import com.alibaba.p3c.idea.config.P3cConfig
import com.alibaba.p3c.idea.inspection.AliBaseInspection
import com.alibaba.smartfox.idea.common.util.BalloonNotifications
import com.intellij.analysis.AnalysisScope
import com.intellij.codeInspection.InspectionManager
import com.intellij.codeInspection.LocalInspectionTool
import com.intellij.codeInspection.ex.InspectionManagerEx
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.Computable
import com.intellij.openapi.util.Ref
import com.intellij.openapi.vcs.CheckinProjectPanel
import com.intellij.openapi.vcs.VcsBundle
import com.intellij.openapi.vcs.changes.CommitExecutor
import com.intellij.openapi.vcs.checkin.CheckinHandler
import com.intellij.openapi.vcs.checkin.CheckinHandlerUtil
import com.intellij.openapi.vcs.ui.RefreshableOnComponent
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiManager
import com.intellij.ui.NonFocusableCheckBox
import com.intellij.util.ExceptionUtil
import com.intellij.util.PairConsumer
import java.awt.BorderLayout
import java.util.ArrayList
import java.util.Arrays
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import javax.swing.JComponent
import javax.swing.JPanel
/**
*
* @author yaohui.wyh
* @date 2017/03/21
* @author caikang
* @date 2017/05/04
*/
class AliCodeAnalysisCheckinHandler(
private val myProject: Project,
private val myCheckinPanel: CheckinProjectPanel
) : CheckinHandler() {
private val dialogTitle = "Alibaba Code Analyze"
private val cancelText = "&Cancel"
private val commitText = "&Commit Anyway"
private val waitingText = "Wait"
val log = Logger.getInstance(javaClass)
override fun getBeforeCheckinConfigurationPanel(): RefreshableOnComponent? {
val checkBox = NonFocusableCheckBox("Alibaba Code Guidelines")
return object : RefreshableOnComponent {
override fun getComponent(): JComponent {
val panel = JPanel(BorderLayout())
panel.add(checkBox)
val dumb = DumbService.isDumb(myProject)
checkBox.isEnabled = !dumb
checkBox.toolTipText = if (dumb) {
"Code analysis is impossible until indices are up-to-date"
} else {
""
}
return panel
}
override fun refresh() {}
override fun saveState() {
getSettings().analysisBeforeCheckin = checkBox.isSelected
}
override fun restoreState() {
checkBox.isSelected = getSettings().analysisBeforeCheckin
}
}
}
private fun getSettings(): P3cConfig {
return ServiceManager.getService(P3cConfig::class.java)
}
override fun beforeCheckin(
executor: CommitExecutor?,
additionalDataConsumer: PairConsumer
): CheckinHandler.ReturnResult {
if (!getSettings().analysisBeforeCheckin) {
return CheckinHandler.ReturnResult.COMMIT
}
if (DumbService.getInstance(myProject).isDumb) {
if (Messages.showOkCancelDialog(
myProject,
"Code analysis is impossible until indices are up-to-date", dialogTitle,
waitingText, commitText, null
) == Messages.OK
) {
return CheckinHandler.ReturnResult.CANCEL
}
return CheckinHandler.ReturnResult.COMMIT
}
val virtualFiles = CheckinHandlerUtil.filterOutGeneratedAndExcludedFiles(myCheckinPanel.virtualFiles, myProject)
val hasViolation = hasViolation(virtualFiles, myProject)
if (!hasViolation) {
BalloonNotifications.showSuccessNotification(
"No suspicious code found!",
myProject, "Analyze Finished"
)
return CheckinHandler.ReturnResult.COMMIT
}
if (Messages.showOkCancelDialog(
myProject, "Found suspicious code,continue commit?",
dialogTitle, commitText, cancelText, null
) == Messages.OK
) {
return CheckinHandler.ReturnResult.COMMIT
} else {
doAnalysis(myProject, virtualFiles.toTypedArray())
return CheckinHandler.ReturnResult.CLOSE_WINDOW
}
}
fun doAnalysis(project: Project, virtualFiles: Array) {
val managerEx = InspectionManager.getInstance(project) as InspectionManagerEx
val analysisScope = AnalysisScope(
project,
ArrayList(Arrays.asList(*virtualFiles))
)
val tools = Inspections.aliInspections(project) { it.tool is AliBaseInspection }
AliInspectionAction.createContext(tools, managerEx, null, false, analysisScope)
.doInspections(analysisScope)
}
private fun hasViolation(virtualFiles: List, project: Project): Boolean {
ApplicationManager.getApplication().assertIsDispatchThread()
PsiDocumentManager.getInstance(myProject).commitAllDocuments()
if (ApplicationManager.getApplication().isWriteAccessAllowed) throw RuntimeException(
"Must not run under write action"
)
val result = AtomicBoolean(false)
val exception = Ref.create()
ProgressManager.getInstance().run(
object : Task.Modal(myProject, VcsBundle.message("checking.code.smells.progress.title"), true) {
override fun run(progress: ProgressIndicator) {
try {
val tools = Inspections.aliInspections(project) { it.tool is AliBaseInspection }
val inspectionManager = InspectionManager.getInstance(project)
val psiManager = PsiManager.getInstance(project)
val count = AtomicInteger(0)
val hasViolation = virtualFiles.asSequence().any { file ->
ApplicationManager.getApplication().runReadAction(Computable {
val psiFile = psiManager.findFile(file) ?: return@Computable false
val curCount = count.incrementAndGet()
progress.text = file.canonicalPath
progress.fraction = curCount.toDouble() / virtualFiles.size.toDouble()
return@Computable tools.any {
progress.checkCanceled()
val tool = it.tool as LocalInspectionTool
val aliTool = tool as AliBaseInspection
progress.text2 = aliTool.ruleName()
val problems = tool.processFile(psiFile, inspectionManager)
problems.size > 0
}
})
}
result.set(hasViolation)
} catch (e: ProcessCanceledException) {
result.set(false)
} catch (e: Exception) {
log.error(e)
exception.set(e)
}
}
})
if (!exception.isNull) {
val t = exception.get()
ExceptionUtil.rethrowAllAsUnchecked(t)
}
return result.get()
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/p3c/idea/vcs/AliCodeAnalysisCheckinHandlerFactory.kt
================================================
/*
* 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.vcs
import com.intellij.openapi.vcs.CheckinProjectPanel
import com.intellij.openapi.vcs.changes.CommitContext
import com.intellij.openapi.vcs.checkin.CheckinHandler
import com.intellij.openapi.vcs.checkin.CheckinHandlerFactory
/**
*
*
* @author caikang
* @date 2017/05/04
*/
class AliCodeAnalysisCheckinHandlerFactory : CheckinHandlerFactory() {
override fun createHandler(panel: CheckinProjectPanel, commitContext: CommitContext): CheckinHandler {
return AliCodeAnalysisCheckinHandler(panel.project, panel)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/component/AliBaseApplicationComponent.kt
================================================
/*
* 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.idea.common.component
import com.alibaba.smartfox.idea.common.util.PluginVersions
import com.intellij.openapi.components.ApplicationComponent
/**
*
*
* @author caikang
* @date 2017/05/11
*/
interface AliBaseApplicationComponent : ApplicationComponent {
override fun getComponentName(): String {
return "${PluginVersions.pluginId.idString}-${javaClass.name}"
}
override fun disposeComponent() {
}
override fun initComponent() {
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/component/AliBaseProjectComponent.kt
================================================
/*
* 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.idea.common.component
import com.alibaba.smartfox.idea.common.util.PluginVersions
import com.intellij.openapi.components.ProjectComponent
/**
*
*
* @author caikang
* @date 2017/04/28
*/
interface AliBaseProjectComponent : ProjectComponent {
override fun getComponentName(): String {
return "${PluginVersions.pluginId.idString}-${javaClass.name}"
}
override fun disposeComponent() {
}
override fun projectClosed() {
}
override fun initComponent() {
}
override fun projectOpened() {
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/util/BalloonNotifications.kt
================================================
/*
* 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.idea.common.util
import com.intellij.notification.NotificationDisplayType
import com.intellij.notification.NotificationGroup
import com.intellij.notification.NotificationListener
import com.intellij.notification.NotificationType
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.ui.Messages
import java.awt.Component
import java.net.UnknownHostException
/**
*
*
* @author caikang
* @date 2017/05/08
*/
object BalloonNotifications {
val displayId = "SmartFox Intellij IDEA Balloon Notification"
val balloonGroup = NotificationGroup(displayId, NotificationDisplayType.BALLOON, true)
val stickyBalloonDisplayId = "SmartFox Intellij IDEA Notification"
val stickyBalloonGroup = NotificationGroup(stickyBalloonDisplayId, NotificationDisplayType.STICKY_BALLOON, true)
val TITLE = "SmartFox Intellij IDEA Plugin"
fun showInfoDialog(component: Component, title: String, message: String) {
Messages.showInfoMessage(component, message, title)
}
fun showErrorDialog(component: Component, title: String, errorMessage: String) {
Messages.showErrorDialog(component, errorMessage, title)
}
fun showErrorDialog(component: Component, title: String, e: Exception) {
if (isOperationCanceled(e)) {
return
}
Messages.showErrorDialog(component, getErrorTextFromException(e), title)
}
fun showSuccessNotification(message: String, project: Project? = ProjectManager.getInstance().defaultProject,
title: String = TITLE, sticky: Boolean = false) {
showNotification(message, project, title, NotificationType.INFORMATION, null, sticky)
}
fun showWarnNotification(message: String, project: Project? = ProjectManager.getInstance().defaultProject,
title: String = TITLE, sticky: Boolean = false) {
showNotification(message, project, title, NotificationType.WARNING, null, sticky)
}
fun showErrorNotification(message: String, project: Project? = ProjectManager.getInstance().defaultProject,
title: String = TITLE, sticky: Boolean = false) {
showNotification(message, project, title, NotificationType.ERROR, null, sticky)
}
fun showSuccessNotification(message: String, project: Project?,
notificationListener: NotificationListener, title: String = TITLE, sticky: Boolean = false) {
showNotification(message, project, title, NotificationType.INFORMATION, notificationListener, sticky)
}
fun showNotification(message: String, project: Project? = ProjectManager.getInstance().defaultProject,
title: String = TITLE,
notificationType: NotificationType = NotificationType.INFORMATION,
notificationListener: NotificationListener? = null, sticky: Boolean = false) {
val group = if (sticky) {
stickyBalloonGroup
} else {
balloonGroup
}
group.createNotification(title, message, notificationType, notificationListener).notify(project)
}
private fun isOperationCanceled(e: Exception): Boolean {
return e is ProcessCanceledException
}
fun getErrorTextFromException(e: Exception): String {
if (e is UnknownHostException) {
return "Unknown host: " + e.message
}
return e.message ?: ""
}
}
object LogNotifications {
val group = NotificationGroup(BalloonNotifications.displayId, NotificationDisplayType.NONE, true)
fun log(message: String, project: Project? = ProjectManager.getInstance().defaultProject,
title: String = BalloonNotifications.TITLE,
notificationType: NotificationType = NotificationType.INFORMATION,
notificationListener: NotificationListener? = null) {
group.createNotification(title, message, notificationType, notificationListener).notify(project)
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/util/CommonExtensions.kt
================================================
/*
* 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.idea.common.util
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
/**
*
*
* @author caikang
* @date 2017/06/19
*/
fun Class.getService(): T {
return ServiceManager.getService(this)
}
fun Class.getService(project: Project): T {
return ServiceManager.getService(project, this)
}
================================================
FILE: idea-plugin/p3c-common/src/main/kotlin/com/alibaba/smartfox/idea/common/util/PluginVersions.kt
================================================
/*
* 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.idea.common.util
import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.ide.plugins.PluginManager
import com.intellij.ide.plugins.cl.PluginClassLoader
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.extensions.PluginId
/**
* @author caikang
*/
object PluginVersions {
val baseVersion141 = 141
val baseVersion143 = 143
val baseVersion145 = 145
val baseVersion162 = 162
val baseVersion163 = 163
val baseVersion171 = 171
val pluginId: PluginId = (javaClass.classLoader as PluginClassLoader).pluginId
val pluginDescriptor: IdeaPluginDescriptor = PluginManager.getPlugin(pluginId)!!
/**
* 获取当前安装的 plugin版本
*/
val pluginVersion: String
get() = pluginDescriptor.version
/**
* 获取当前使用的IDE版本
*/
val ideVersion: String
get() {
val applicationInfo = ApplicationInfo.getInstance()
return applicationInfo.fullVersion + "_" + applicationInfo.build
}
val baseVersion: Int
get() {
val applicationInfo = ApplicationInfo.getInstance()
return applicationInfo.build.baselineVersion
}
}
================================================
FILE: idea-plugin/p3c-common/src/main/resources/messages/P3cBundle.xml
================================================
阿里编码规约
切换语言至英文(English)
切换语言至中文
重启后生效]]>
编码规约扫描
关闭实时检测功能
打开实时检测功能
删除开头的 $ 或者 _
添加/提取 @author
修正为以下划线分隔大写模式
修改为小写驼峰命名(lowerCamelCase)
为变量添加!
替换为
通过类 '%s' 直接访问静态成员
'%s.%s'
添加 @Override 注解
为语句加上大括号
翻转 equals 调用
修改为 String[] str 模式
'l' 替换为 'L'
#ref #loc]]>
避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。
不应该通过类实例访问静态成员
%s #loc
不能使用过时的类或方法。
所有的覆写方法,必须加@Override注解。
#ref()缺少 '@Override' 注解 #loc]]>
Map/Set的key为自定义对象时,必须重写hashCode和equals。
参数类型 %s 没有重写hashCode和equals #loc
#ref 是非线程安全的,请加锁或者使用局部变量 #loc]]>
#ref 没有加大括号 #loc]]>
#ref 应该作为方法 "%s()"的调用方,而不是参数 #loc]]>
#ref 数组定义格式错误 #loc]]>
#ref 应该以大写L结尾 #loc]]>
#ref #loc]]>
避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。