From 99c612378de7404ae9d838a580923edb05de48b5 Mon Sep 17 00:00:00 2001 From: Guo XIn <371864209@qq.com> Date: Sun, 14 Jan 2024 14:11:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84=E5=8F=AF=E8=AE=A2=E9=98=85?= =?UTF-8?q?=E7=9A=84=E8=8A=82=E7=82=B9=E8=AE=BF=E9=97=AE=E5=99=A8=E6=8A=BD?= =?UTF-8?q?=E8=B1=A1=E7=B1=BB=EF=BC=8C=E5=B9=B6=E6=94=B9=E9=80=A0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E8=A7=84=E5=88=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sonar/cxx/SubscriptionAstVisitor.java | 112 ++++++++++++++++++ .../cxx/rules/checkers/ABCVarNameChecker.java | 48 ++++++-- 2 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/SubscriptionAstVisitor.java diff --git a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/SubscriptionAstVisitor.java b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/SubscriptionAstVisitor.java new file mode 100644 index 0000000..5a69849 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/SubscriptionAstVisitor.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:C++ 信息安全性设计准则 + * 项目描述:用于检查C++源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ +package com.keyware.sonar.cxx; + +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.AstNodeType; +import com.sonar.cxx.sslr.api.Grammar; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +import java.util.List; + +/** + * 可自由订阅的语法树节点访问器 + * + * @author GuoXin + * @date 2024/1/13 + */ +public abstract class SubscriptionAstVisitor extends SquidCheck { + /** + * 构造函数需要传入初代访问器 + * + * @param checker 初代规则检查器 + */ + public SubscriptionAstVisitor(SquidCheck checker) { + setContext(checker.getContext()); + visitNodeTypes().forEach(this::subscribeTo); + } + + /** + * 对指定的节点进行访问操作 + * + * @param node 需要访问的节点 + */ + public void accept(AstNode node) { + this.visit(node); + } + + /** + * 获取该访问器所需要访问的节点类型列表 + * + * @return 节点类型列表 + */ + public abstract List visitNodeTypes(); + + /** + * 对指定的节点进行访问 + * + * @param node 待访问的节点 + */ + private void visit(AstNode node) { + boolean isSubscribed = isSubscribed(node); + if (isSubscribed) { + visitNode(node); + } + visitChildren(node); + if (isSubscribed) { + leaveNode(node); + } + } + + /** + * 对指定节点的子节点进行访问 + * + * @param node 待访问的节点 + */ + private void visitChildren(AstNode node) { + if (node.hasChildren()) { + for (AstNode next : node.getChildren()) { + if (next != null) { + visit(next); + } + } + } + } + + /** + * 判断指定节点是否被订阅 + * + * @param tree 待判断的节点 + * @return true表示被订阅,false表示未订阅 + */ + private boolean isSubscribed(AstNode tree) { + return getAstNodeTypesToVisit().contains(tree.getType()); + } + + + /** + * 创建由给定 AST 节点导致的文件级问题 + * + * @param message 描述违规的消息,可以格式化(参见 java.text.MessageFormat) + * @param messageParameters 可选消息参数(请参阅 java.text.MessageFormat) + */ + protected void reportIssue(String message, Object... messageParameters) { + getContext().createFileViolation(this, message, messageParameters); + } + + /** + * 创建由给定 AST 节点导致的行级问题 + * + * @param node 导致问题的 AST 节点 + * @param message 描述违规的消息,可以格式化(参见 java.text.MessageFormat) + * @param messageParameters 可选消息参数(请参阅 java.text.MessageFormat) + */ + protected void reportIssue(AstNode node, String message, Object... messageParameters) { + getContext().createLineViolation(this, message, node, messageParameters); + } +} + diff --git a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/ABCVarNameChecker.java b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/ABCVarNameChecker.java index 20adf10..f591304 100644 --- a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/ABCVarNameChecker.java +++ b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/ABCVarNameChecker.java @@ -6,7 +6,9 @@ */ package com.keyware.sonar.cxx.rules.checkers; +import com.keyware.sonar.cxx.SubscriptionAstVisitor; import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.AstNodeType; import com.sonar.cxx.sslr.api.Grammar; import org.sonar.check.Priority; import org.sonar.check.Rule; @@ -15,6 +17,9 @@ import org.sonar.cxx.squidbridge.annotations.ActivatedByDefault; import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation; import org.sonar.cxx.squidbridge.checks.SquidCheck; +import javax.annotation.Nonnull; +import java.util.List; + import static com.sonar.cxx.sslr.api.GenericTokenType.IDENTIFIER; /** @@ -33,24 +38,47 @@ public class ABCVarNameChecker extends SquidCheck { */ @Override public void init() { - // 订阅要检查AST节点类型,用于在visitNode方法中检查该类型节点 + // 指定当前访问器需要访问的节点类型,functionDefinition(方法声明)节点类型 this.subscribeTo( - CxxGrammarImpl.declaratorId + CxxGrammarImpl.functionDefinition ); } /** - * 检查AST节点 + * 访问AST节点 * - * @param astNode 要处理的AST节点,该节点类型为通过subscribeTo方法订阅的类型 + * @param node 要处理的AST节点,该节点类型为通过subscribeTo方法订阅的类型 */ @Override - public void visitNode(AstNode astNode) { - var idNode = astNode.getLastChild(IDENTIFIER); - if (idNode != null) { - String identifier = idNode.getTokenValue(); - if ("ABC".equals(identifier)) { - getContext().createLineViolation(this, "变量名称不可以是ABC", idNode); + public void visitNode(@Nonnull AstNode node) { + var visitor = new SimpleDeclarationVisitor(this); + visitor.accept(node); + } + + /** + * 自定义一个AST节点访问器,这里用于访问simpleDeclaration(简单声明)节点 + */ + static class SimpleDeclarationVisitor extends SubscriptionAstVisitor { + + public SimpleDeclarationVisitor(SquidCheck checker) { + super(checker); + } + + @Override + public List visitNodeTypes() { + // 指定当前访问器需要访问的节点类型,这里指定了simpleDeclaration(简单声明)节点类型 + return List.of(CxxGrammarImpl.simpleDeclaration); + } + + @Override + public void visitNode(AstNode node) { + // 获取第一个后代 + var idNode = node.getFirstDescendant(IDENTIFIER); + if (idNode != null) { + String identifier = idNode.getTokenValue(); + if ("ABC".equals(identifier)) { + reportIssue(idNode, "变量名称不可以是ABC"); + } } } }