创建Idea静态代码扫描工具
背景
近期公司框架升级,代码和配置的变动较大。为了保证升级的质量,开发了一个静态代码扫描工具,供所有开发者使用。此工具专注于检查异步方法中线程变量(例如myThreadlocal
)的使用情况。
项目设置
版本
- JDK 1.8
- IntelliJ IDEA 2022
- 基于 Gradle 构建插件
项目创建步骤
1. 新建项目
使用 IntelliJ IDEA 创建一个新的 Gradle 项目,并配置基本的项目结构。
2. 创建异步方法扫描类
新建一个 Java 类 AsyncInspection
来定义扫描逻辑。
package com.dxz.demo; import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; public class AsyncInspection extends AbstractBaseJavaLocalInspectionTool { private static final Logger LOG = Logger.getInstance(AsyncInspection.class); @Override @NotNull public String getShortName() { return "AsyncInspection"; } @Override public String getGroupDisplayName() { return "WalletInspection"; } @Override public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { return new JavaElementVisitor() { @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) { super.visitMethodCallExpression(expression); if (isAsyncMethodCall(expression)) { LOG.info("AsyncInspection " + expression.getText()); checkTntCodeUsage(expression, holder); } } @Override public void visitAnnotation(PsiAnnotation annotation) { super.visitAnnotation(annotation); if (isAsyncAnnotation(annotation)) { PsiElement parent = annotation.getParent().getParent(); if (parent instanceof PsiMethod) { PsiMethod method = (PsiMethod) parent; checkTntCodeUsage(method.getBody(), holder); } } } }; } private boolean isAsyncMethodCall(PsiMethodCallExpression expression) { String methodName = expression.getMethodExpression().getReferenceName(); return "runAsync".equals(methodName) || "supplyAsync".equals(methodName); } private boolean isAsyncAnnotation(PsiAnnotation annotation) { String qualifiedName = annotation.getQualifiedName(); return "org.springframework.scheduling.annotation.Async".equals(qualifiedName); } private void checkTntCodeUsage(PsiElement element, ProblemsHolder holder) { if (element != null && !containsTntCode(element)) { holder.registerProblem(element, "Possible missing myThreadlocal usage in async method."); } } private boolean containsTntCode(PsiElement element) { if (element instanceof PsiReferenceExpression) { String text = element.getText(); if (text.contains("MyThreadlocal") || text.contains("myThreadlocal")) { return true; } } for (PsiElement child : element.getChildren()) { if (containsTntCode(child)) { return true; } } return false; } }
3. 配置 Gradle 构建脚本
在 build.gradle
中添加以下内容:
plugins { id 'java' id 'org.jetbrains.intellij' version '1.8.0' } group = 'com.dxz' version = '1.0.2.2021.3' repositories { mavenCentral() } intellij { version.set('2021.3.3') type.set('IC') plugins.set(['com.intellij.java']) } dependencies { implementation 'org.jetbrains:annotations:21.0.1' } tasks.withType(JavaCompile) { sourceCompatibility = '11' targetCompatibility = '11' } patchPluginXml { sinceBuild.set('213') untilBuild.set('223.*') } signPlugin { certificateChain.set(System.getenv('CERTIFICATE_CHAIN')) privateKey.set(System.getenv('PRIVATE_KEY')) password.set(System.getenv('PRIVATE_KEY_PASSWORD')) } publishPlugin { token.set(System.getenv('PUBLISH_TOKEN')) }
4. 配置 plugin.xml
创建 plugin.xml
文件以配置插件元数据:
<idea-plugin> <id>com.dxz.demo</id> <name>demo-inspection</name> <vendor email="duanxz@xx.com" url="https://www.yourcompany.com">duanxz</vendor> <description><![CDATA[ 我的第一个扫描工具,异步方法中的线程变量处理检测。 ]]></description> <depends>com.intellij.modules.platform</depends> <extensions defaultExtensionNs="com.intellij"> <localInspection language="JAVA" shortName="AsyncInspection" displayName="Absence of myThreadlocal Inspection" groupDisplayName="Wallet Inspections" implementationClass="com.dxz.AsyncInspection"/> </extensions> </idea-plugin>
5. 打包构建
在 IntelliJ IDEA 中,使用 gradle buildPlugin
命令进行构建。成功后,在 build/distributions
目录下会生成相应的 zip 文件。
6. 插件安装与使用
在 IDEA 中安装生成的插件,然后从菜单栏选择 Code -> Inspect Code
运行静态代码扫描。
总结
通过这个静态扫描工具,可以有效地检查异步方法中的线程变量使用情况,确保代码质量,为框架升级提供保障。