diff --git a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.java b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.java index 7eb29a5..abbac5e 100644 --- a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.java +++ b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.java @@ -6,7 +6,9 @@ */ package com.keyware.sonar.cxx.rules.checkers; + import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.GenericTokenType; 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 java.util.HashSet; +import java.util.Set; + /** * 在访问文件或目录前对路径名进行验证 @@ -27,68 +32,85 @@ import org.sonar.cxx.squidbridge.checks.SquidCheck; @ActivatedByDefault @SqaleConstantRemediation("5min") public class FileAccessChecker extends SquidCheck { - private boolean filePathChecked = false; - private boolean filePathUsedInIf = false; + + private Set conditionVariables; @Override public void init() { - subscribeTo(CxxGrammarImpl.selectionStatement, CxxGrammarImpl.declaration, CxxGrammarImpl.statement); + subscribeTo(CxxGrammarImpl.selectionStatement); + subscribeTo(CxxGrammarImpl.declaration); + conditionVariables = new HashSet<>(); } @Override - public void visitNode(AstNode astNode) { - if (astNode.is(CxxGrammarImpl.selectionStatement)) { - checkIfStatement(astNode); - } else if (astNode.is(CxxGrammarImpl.declaration)) { - checkDeclaration(astNode); - } else if (astNode.is(CxxGrammarImpl.statement)) { - checkStatement(astNode); + public void visitNode(AstNode node) { + if (node.is(CxxGrammarImpl.selectionStatement)) { + handleIfStatement(node); + } else if (node.is(CxxGrammarImpl.declaration)) { + addAllIdentifiers(node); + handleDeclaration(node); } } - private void checkIfStatement(AstNode ifStatement) { - AstNode condition = ifStatement.getFirstChild(CxxGrammarImpl.condition); - filePathUsedInIf = containsFilePathCheck(condition); - if (!filePathUsedInIf) { - createViolation(ifStatement, "在访问文件或目录前需要对路径名进行验证"); + + private void handleDeclaration(AstNode node) { + AstNode ifstreamNode = findIfstreamNode(node); + if (ifstreamNode != null) { + handleIfstreamDeclaration(ifstreamNode); } - filePathUsedInIf = false; } - private void checkDeclaration(AstNode declaration) { - AstNode declaratorNode = declaration.getFirstDescendant(CxxGrammarImpl.declarator); - filePathChecked = containsFilePathCheck(declaratorNode); - if (declaratorNode != null && !filePathChecked) { - String variableName = declaratorNode.getTokenOriginalValue(); - if (variableName != null && variableName.equals("filePath")) { - System.out.println(variableName); - getContext().createLineViolation(this, "在访问文件或目录前需要对路径名进行验证", declaratorNode); + private AstNode findIfstreamNode(AstNode node) { + if (node.getToken() != null && "ifstream".equals(node.getTokenOriginalValue())) { + return node; + } + for (AstNode child : node.getChildren()) { + AstNode result = findIfstreamNode(child); + if (result != null) { + return result; } } + return null; } - private void checkStatement(AstNode statement) { - AstNode condition = statement.getFirstChild(CxxGrammarImpl.condition); - filePathChecked = containsFilePathCheck(condition); - } - private boolean containsFilePathCheck(AstNode node) { - if (node != null && node.getTokenOriginalValue().equals("filePath")) { - return true; + private void handleIfStatement(AstNode node) { + AstNode conditionNode = node.getFirstDescendant(CxxGrammarImpl.condition); + if (conditionNode != null) { + addAllIdentifiers(conditionNode); } - if (node != null) { - for (AstNode child : node.getChildren()) { - // 如果 if 中使用了 filePath,则停止递归并跳过 ifstream file(filePath) 检查 - if (containsFilePathCheck(child)) { - return true; + } + + private void addAllIdentifiers(AstNode node) { + for (AstNode child : node.getChildren()) { + if (child.getType().equals(CxxGrammarImpl.selectionStatement)) { + // 找到 if 语句节点 + AstNode conditionNode = child.getFirstDescendant(CxxGrammarImpl.condition); + // 找到条件部分的节点 + AstNode identifierNode = conditionNode.getFirstDescendant(GenericTokenType.IDENTIFIER); + // 找到代表标识符的节点 + if (identifierNode != null) { + String codeInsideIf = identifierNode.getTokenValue(); + // 获取标识符节点的值 + conditionVariables.add(codeInsideIf); } + } else { + addAllIdentifiers(child); } } - return false; // 节点或其任何子节点中找不到“filePath” } - private void createViolation(AstNode node, String message) { - getContext().createLineViolation(this, message, node); + private void handleIfstreamDeclaration(AstNode ifstreamNode) { + AstNode parameterDeclarationNode = ifstreamNode.getFirstDescendant(CxxGrammarImpl.parameterDeclaration); + if (parameterDeclarationNode != null) { + AstNode identifierNode = parameterDeclarationNode.getFirstDescendant(GenericTokenType.IDENTIFIER); + if (identifierNode != null) { + String ifstreamParam = identifierNode.getTokenOriginalValue(); + if (!conditionVariables.contains(ifstreamParam)) { + getContext().createLineViolation(this, "在访问文件或目录前需要对路径名进行验证", ifstreamNode); + } + } + } } } diff --git a/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/FileAccessCheckerTest.java b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/FileAccessCheckerTest.java index a7a2598..a2ad779 100644 --- a/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/FileAccessCheckerTest.java +++ b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/FileAccessCheckerTest.java @@ -27,7 +27,7 @@ public class FileAccessCheckerTest { var tester = CxxFileTesterHelper.create("FileAccessChecker.cc"); SourceFile file = CxxAstScanner.scanSingleInputFile(tester.asInputFile(), checker); CheckMessagesVerifier.verify(file.getCheckMessages()) - .next().atLine(13).withMessage("在访问文件或目录前需要对路径名进行验证") + .next().atLine(14).withMessage("在访问文件或目录前需要对路径名进行验证") .noMore(); } } diff --git a/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.cc b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.cc index 41b8d46..0d4dd4a 100644 --- a/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.cc +++ b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/FileAccessChecker.cc @@ -10,7 +10,7 @@ int main() { int a = 5; - if (a<5) { + if (a<4) { ifstream file(filePath); cout << "File opened successfully." << endl;