优化:增加自定义的可订阅的节点访问器抽象类,并改造示例规则代码

wuhaoyang
Guo XIn 8 months ago
parent 46fff96588
commit 99c612378d
  1. 112
      sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/SubscriptionAstVisitor.java
  2. 48
      sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/ABCVarNameChecker.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<Grammar> {
/**
* 构造函数需要传入初代访问器
*
* @param checker 初代规则检查器
*/
public SubscriptionAstVisitor(SquidCheck<Grammar> checker) {
setContext(checker.getContext());
visitNodeTypes().forEach(this::subscribeTo);
}
/**
* 对指定的节点进行访问操作
*
* @param node 需要访问的节点
*/
public void accept(AstNode node) {
this.visit(node);
}
/**
* 获取该访问器所需要访问的节点类型列表
*
* @return 节点类型列表
*/
public abstract List<AstNodeType> 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);
}
}

@ -6,7 +6,9 @@
*/ */
package com.keyware.sonar.cxx.rules.checkers; 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.AstNode;
import com.sonar.cxx.sslr.api.AstNodeType;
import com.sonar.cxx.sslr.api.Grammar; import com.sonar.cxx.sslr.api.Grammar;
import org.sonar.check.Priority; import org.sonar.check.Priority;
import org.sonar.check.Rule; 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.annotations.SqaleConstantRemediation;
import org.sonar.cxx.squidbridge.checks.SquidCheck; import org.sonar.cxx.squidbridge.checks.SquidCheck;
import javax.annotation.Nonnull;
import java.util.List;
import static com.sonar.cxx.sslr.api.GenericTokenType.IDENTIFIER; import static com.sonar.cxx.sslr.api.GenericTokenType.IDENTIFIER;
/** /**
@ -33,24 +38,47 @@ public class ABCVarNameChecker extends SquidCheck<Grammar> {
*/ */
@Override @Override
public void init() { public void init() {
// 订阅要检查AST节点类型,用于在visitNode方法中检查该类型节点 // 指定当前访问器需要访问的节点类型,functionDefinition(方法声明)节点类型
this.subscribeTo( this.subscribeTo(
CxxGrammarImpl.declaratorId CxxGrammarImpl.functionDefinition
); );
} }
/** /**
* 检查AST节点 * 访问AST节点
* *
* @param astNode 要处理的AST节点该节点类型为通过subscribeTo方法订阅的类型 * @param node 要处理的AST节点该节点类型为通过subscribeTo方法订阅的类型
*/ */
@Override @Override
public void visitNode(AstNode astNode) { public void visitNode(@Nonnull AstNode node) {
var idNode = astNode.getLastChild(IDENTIFIER); var visitor = new SimpleDeclarationVisitor(this);
if (idNode != null) { visitor.accept(node);
String identifier = idNode.getTokenValue(); }
if ("ABC".equals(identifier)) {
getContext().createLineViolation(this, "变量名称不可以是ABC", idNode); /**
* 自定义一个AST节点访问器这里用于访问simpleDeclaration简单声明节点
*/
static class SimpleDeclarationVisitor extends SubscriptionAstVisitor {
public SimpleDeclarationVisitor(SquidCheck<Grammar> checker) {
super(checker);
}
@Override
public List<AstNodeType> 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");
}
} }
} }
} }

Loading…
Cancel
Save