diff --git a/.gitignore b/.gitignore
index dbcf57e71..7ca76c60c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,14 @@ target/
!**/src/main/**/target/
!**/src/test/**/target/
+### Generated scan output ###
+cbom.json
+maven_fast/
+*.tokens
+*.interp
+generated-sources/
+.antlr/
+
### IntelliJ IDEA ###
.idea
*.iws
diff --git a/cxx/pom.xml b/cxx/pom.xml
new file mode 100644
index 000000000..47ba9a1a8
--- /dev/null
+++ b/cxx/pom.xml
@@ -0,0 +1,63 @@
+
+
+ 4.0.0
+
+ com.ibm
+ sonar-cryptography
+ 2.0.0-SNAPSHOT
+
+
+ cxx
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ com.ibm
+ engine
+ 2.0.0-SNAPSHOT
+
+
+ com.ibm
+ output
+ 2.0.0-SNAPSHOT
+
+
+ com.ibm
+ enricher
+ 2.0.0-SNAPSHOT
+
+
+ com.ibm
+ rules
+ 2.0.0-SNAPSHOT
+
+
+ com.ibm
+ common
+ 2.0.0-SNAPSHOT
+
+
+ com.ibm
+ mapper
+ 2.0.0-SNAPSHOT
+
+
+
+
+
+
+ org.sonarsource.analyzer-commons
+ sonar-analyzer-test-commons
+ 2.18.0.3393
+ test
+
+
+
+
diff --git a/cxx/src/main/java/com/ibm/plugin/CryptoCxxSensor.java b/cxx/src/main/java/com/ibm/plugin/CryptoCxxSensor.java
new file mode 100644
index 000000000..63bce6b6b
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/CryptoCxxSensor.java
@@ -0,0 +1,133 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin;
+
+import com.ibm.engine.language.cxx.CxxCheck;
+import com.ibm.engine.language.cxx.CxxParserErrorListener;
+import com.ibm.engine.language.cxx.CxxScanContext;
+import com.ibm.engine.language.cxx.antlr.CPP14Lexer;
+import com.ibm.engine.language.cxx.antlr.CPP14Parser;
+import java.io.IOException;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+
+public class CryptoCxxSensor implements Sensor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CryptoCxxSensor.class);
+
+ private final Collection checks;
+
+ public CryptoCxxSensor(@Nonnull CheckFactory checkFactory) {
+ this.checks =
+ checkFactory
+ .create(CxxScannerRuleDefinition.REPOSITORY_KEY)
+ .addAnnotatedChecks(CxxRuleList.getChecks())
+ .all();
+ }
+
+ @Override
+ public void describe(@Nonnull SensorDescriptor descriptor) {
+ descriptor.onlyOnLanguage("cpp").name("Cryptography for C++");
+ }
+
+ @Override
+ public void execute(@Nonnull SensorContext context) {
+ if (checks.isEmpty()) {
+ return;
+ }
+
+ FileSystem fs = context.fileSystem();
+ Iterable cxxFiles =
+ fs.inputFiles(
+ fs.predicates()
+ .and(
+ fs.predicates().hasLanguage("cpp"),
+ fs.predicates().hasType(InputFile.Type.MAIN)));
+
+ for (InputFile inputFile : cxxFiles) {
+ if (context.isCancelled()) {
+ return;
+ }
+ analyzeFile(context, inputFile);
+ }
+ }
+
+ private void analyzeFile(@Nonnull SensorContext context, @Nonnull InputFile inputFile) {
+ String content;
+ try {
+ content = inputFile.contents();
+ } catch (IOException e) {
+ LOG.warn("Unable to read file: {}", inputFile, e);
+ return;
+ }
+
+ CPP14Parser.TranslationUnitContext parseTree = parseContent(content, inputFile);
+ if (parseTree == null) {
+ return;
+ }
+
+ CxxScanContext scanContext =
+ new CxxScanContext(context, inputFile, CxxScannerRuleDefinition.REPOSITORY_KEY);
+
+ for (CxxCheck check : checks) {
+ try {
+ check.scan(scanContext, parseTree);
+ } catch (RuntimeException e) {
+ LOG.warn(
+ "Error running check {} on {}: {}",
+ check.getClass().getSimpleName(),
+ inputFile,
+ e.getMessage(),
+ e);
+ }
+ }
+ }
+
+ @Nullable private CPP14Parser.TranslationUnitContext parseContent(
+ @Nonnull String content, @Nonnull InputFile inputFile) {
+ try {
+ CPP14Lexer lexer =
+ new CPP14Lexer(CharStreams.fromString(content, inputFile.toString()));
+ lexer.removeErrorListeners();
+ lexer.addErrorListener(new CxxParserErrorListener(inputFile));
+
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ CPP14Parser parser = new CPP14Parser(tokens);
+ parser.removeErrorListeners();
+ parser.addErrorListener(new CxxParserErrorListener(inputFile));
+
+ return parser.translationUnit();
+ } catch (RuntimeException e) {
+ LOG.warn("Unable to parse file: {}", inputFile, e);
+ return null;
+ }
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/CxxAggregator.java b/cxx/src/main/java/com/ibm/plugin/CxxAggregator.java
new file mode 100644
index 000000000..a125c9c86
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/CxxAggregator.java
@@ -0,0 +1,42 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin;
+
+import com.ibm.mapper.model.INode;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class CxxAggregator {
+ private static final List nodes = new ArrayList<>();
+
+ private CxxAggregator() {}
+
+ public static List getDetectedNodes() {
+ return new ArrayList<>(nodes);
+ }
+
+ public static void addNode(INode node) {
+ nodes.add(node);
+ }
+
+ public static void reset() {
+ nodes.clear();
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/CxxCheckRegistrar.java b/cxx/src/main/java/com/ibm/plugin/CxxCheckRegistrar.java
new file mode 100644
index 000000000..c0d2a69e9
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/CxxCheckRegistrar.java
@@ -0,0 +1,31 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin;
+
+import org.sonar.api.scanner.ScannerSide;
+
+// TODO: Best effort Cxx Check Registrar. Depending on sonar-cxx API, this might need to implement a
+// specific interface.
+@ScannerSide
+public class CxxCheckRegistrar {
+ public void register() {
+ // Implementation for registering custom Cxx rules
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/CxxRuleList.java b/cxx/src/main/java/com/ibm/plugin/CxxRuleList.java
new file mode 100644
index 000000000..f4f213fe4
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/CxxRuleList.java
@@ -0,0 +1,34 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin;
+
+import com.ibm.plugin.rules.CxxInventoryRule;
+import java.util.List;
+
+public final class CxxRuleList {
+
+ private CxxRuleList() {
+ // nothing
+ }
+
+ public static List> getChecks() {
+ return List.of(CxxInventoryRule.class);
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/CxxScannerRuleDefinition.java b/cxx/src/main/java/com/ibm/plugin/CxxScannerRuleDefinition.java
new file mode 100644
index 000000000..f5310b003
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/CxxScannerRuleDefinition.java
@@ -0,0 +1,44 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin;
+
+import org.sonar.api.server.rule.RulesDefinition;
+
+public class CxxScannerRuleDefinition implements RulesDefinition {
+ public static final String REPOSITORY_KEY = "cbomkit-cryptography-cxx";
+
+ @Override
+ public void define(Context context) {
+ NewRepository repository =
+ context.createRepository(REPOSITORY_KEY, "cpp")
+ .setName("CBOMkit Cryptography Repository");
+
+ // Use RuleMetadataLoader to load metadata from annotations and resources
+ // For C++, we might need to manually register if we don't have the resource files yet,
+ // but let's try to follow the pattern or at least register the class.
+ for (Class> checkClass : CxxRuleList.getChecks()) {
+ repository.createRule(checkClass.getAnnotation(org.sonar.check.Rule.class).key())
+ .setName(checkClass.getSimpleName())
+ .setHtmlDescription("Detection rule for C++ cryptographic assets.");
+ }
+
+ repository.done();
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/rules/CxxInventoryRule.java b/cxx/src/main/java/com/ibm/plugin/rules/CxxInventoryRule.java
new file mode 100644
index 000000000..5cbd2ec70
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/rules/CxxInventoryRule.java
@@ -0,0 +1,73 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.rules;
+
+import com.ibm.common.IObserver;
+import com.ibm.engine.detection.Finding;
+import com.ibm.engine.executive.DetectionExecutive;
+import com.ibm.engine.language.cxx.CxxCheck;
+import com.ibm.engine.language.cxx.CxxLanguageSupport;
+import com.ibm.engine.language.cxx.CxxScanContext;
+import com.ibm.engine.language.cxx.CxxSymbol;
+import com.ibm.engine.language.cxx.antlr.CPP14Parser;
+import com.ibm.engine.rule.IDetectionRule;
+import com.ibm.mapper.model.INode;
+import com.ibm.plugin.CxxAggregator;
+import com.ibm.plugin.rules.detection.CxxDetectionRules;
+import com.ibm.plugin.translation.CxxTranslationProcess;
+import com.ibm.plugin.translation.reorganizer.CxxReorganizerRules;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.sonar.check.Rule;
+
+@Rule(key = "CxxInventoryRule")
+public class CxxInventoryRule
+ implements CxxCheck,
+ IObserver> {
+
+ private final List> detectionRules;
+ private final CxxTranslationProcess translationProcess;
+
+ public CxxInventoryRule() {
+ this.detectionRules = CxxDetectionRules.rules();
+ this.translationProcess = new CxxTranslationProcess(CxxReorganizerRules.rules());
+ }
+
+ @Override
+ public void scan(
+ @Nonnull CxxScanContext scanContext, @Nonnull CPP14Parser.TranslationUnitContext tree) {
+ CxxLanguageSupport languageSupport = new CxxLanguageSupport();
+ for (IDetectionRule rule : detectionRules) {
+ DetectionExecutive
+ detectionExecutive =
+ languageSupport.createDetectionExecutive(tree, rule, scanContext);
+ detectionExecutive.subscribe(this);
+ detectionExecutive.start();
+ }
+ }
+
+ @Override
+ public void update(
+ @Nonnull Finding finding) {
+ final List nodes = translationProcess.initiate(finding.detectionStore());
+ nodes.forEach(CxxAggregator::addNode);
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/rules/detection/CxxDetectionRules.java b/cxx/src/main/java/com/ibm/plugin/rules/detection/CxxDetectionRules.java
new file mode 100644
index 000000000..ef23dc3c2
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/rules/detection/CxxDetectionRules.java
@@ -0,0 +1,36 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.rules.detection;
+
+import com.ibm.engine.rule.IDetectionRule;
+import com.ibm.plugin.rules.detection.openssl.OpenSSLDetectionRules;
+import java.util.List;
+import java.util.stream.Stream;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public class CxxDetectionRules {
+ private CxxDetectionRules() {
+ // private
+ }
+
+ public static List> rules() {
+ return Stream.of(OpenSSLDetectionRules.rules().stream()).flatMap(i -> i).toList();
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/rules/detection/openssl/OpenSSLDetectionRules.java b/cxx/src/main/java/com/ibm/plugin/rules/detection/openssl/OpenSSLDetectionRules.java
new file mode 100644
index 000000000..acce5393f
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/rules/detection/openssl/OpenSSLDetectionRules.java
@@ -0,0 +1,35 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.rules.detection.openssl;
+
+import com.ibm.engine.rule.IDetectionRule;
+import java.util.List;
+import java.util.stream.Stream;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public final class OpenSSLDetectionRules {
+ private OpenSSLDetectionRules() {
+ // private
+ }
+
+ public static List> rules() {
+ return Stream.of(OsslEvpRule.rules().stream()).flatMap(i -> i).toList();
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/rules/detection/openssl/OsslEvpRule.java b/cxx/src/main/java/com/ibm/plugin/rules/detection/openssl/OsslEvpRule.java
new file mode 100644
index 000000000..13451a99a
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/rules/detection/openssl/OsslEvpRule.java
@@ -0,0 +1,63 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.rules.detection.openssl;
+
+import com.ibm.engine.rule.IDetectionRule;
+import com.ibm.engine.rule.builder.DetectionRuleBuilder;
+import java.util.List;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public final class OsslEvpRule {
+
+ private OsslEvpRule() {
+ // private
+ }
+
+ public static final IDetectionRule EVP_ENCRYPT_INIT_EX =
+ new DetectionRuleBuilder()
+ .createDetectionRule()
+ .forMethods("EVP_EncryptInit_ex")
+ .withMethodParameter("const EVP_CIPHER *")
+ .buildForContext(new com.ibm.engine.model.context.CipherContext())
+ .inBundle(() -> "OpenSSL")
+ .withoutDependingDetectionRules();
+
+ public static final IDetectionRule EVP_DECRYPT_INIT_EX =
+ new DetectionRuleBuilder()
+ .createDetectionRule()
+ .forMethods("EVP_DecryptInit_ex")
+ .withMethodParameter("const EVP_CIPHER *")
+ .buildForContext(new com.ibm.engine.model.context.CipherContext())
+ .inBundle(() -> "OpenSSL")
+ .withoutDependingDetectionRules();
+
+ public static final IDetectionRule EVP_CIPHER_INIT_EX =
+ new DetectionRuleBuilder()
+ .createDetectionRule()
+ .forMethods("EVP_CipherInit_ex")
+ .withMethodParameter("const EVP_CIPHER *")
+ .buildForContext(new com.ibm.engine.model.context.CipherContext())
+ .inBundle(() -> "OpenSSL")
+ .withoutDependingDetectionRules();
+
+ public static List> rules() {
+ return List.of(EVP_ENCRYPT_INIT_EX, EVP_DECRYPT_INIT_EX, EVP_CIPHER_INIT_EX);
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/translation/CxxTranslationProcess.java b/cxx/src/main/java/com/ibm/plugin/translation/CxxTranslationProcess.java
new file mode 100644
index 000000000..459e14a61
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/translation/CxxTranslationProcess.java
@@ -0,0 +1,66 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.translation;
+
+import com.ibm.engine.detection.DetectionStore;
+import com.ibm.engine.language.cxx.CxxCheck;
+import com.ibm.engine.language.cxx.CxxScanContext;
+import com.ibm.engine.language.cxx.CxxSymbol;
+import com.ibm.enricher.Enricher;
+import com.ibm.mapper.ITranslationProcess;
+import com.ibm.mapper.model.INode;
+import com.ibm.mapper.reorganizer.IReorganizerRule;
+import com.ibm.mapper.reorganizer.Reorganizer;
+import com.ibm.mapper.utils.Utils;
+import com.ibm.plugin.translation.translator.CxxTranslator;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public class CxxTranslationProcess
+ extends ITranslationProcess {
+
+ public CxxTranslationProcess(@Nonnull List reorganizerRules) {
+ super(reorganizerRules);
+ }
+
+ @Nonnull
+ @Override
+ public List initiate(
+ @Nonnull
+ DetectionStore
+ rootDetectionStore) {
+ // 1. Translate
+ final CxxTranslator translator = new CxxTranslator();
+ final List translatedValues = translator.translate(rootDetectionStore);
+ Utils.printNodeTree("translated ", translatedValues);
+
+ // 2. Reorganize
+ final Reorganizer cxxReorganizer = new Reorganizer(reorganizerRules);
+ final List reorganizedValues = cxxReorganizer.reorganize(translatedValues);
+ Utils.printNodeTree("reorganised", reorganizedValues);
+
+ // 3. Enrich
+ final List enrichedValues = Enricher.enrich(reorganizedValues).stream().toList();
+ Utils.printNodeTree("enriched ", enrichedValues);
+
+ return enrichedValues.stream().toList();
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/translation/reorganizer/CxxReorganizerRules.java b/cxx/src/main/java/com/ibm/plugin/translation/reorganizer/CxxReorganizerRules.java
new file mode 100644
index 000000000..5e77e1659
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/translation/reorganizer/CxxReorganizerRules.java
@@ -0,0 +1,29 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.translation.reorganizer;
+
+import com.ibm.mapper.reorganizer.IReorganizerRule;
+import java.util.List;
+
+public class CxxReorganizerRules {
+ public static List rules() {
+ return List.of();
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/translation/translator/CxxTranslator.java b/cxx/src/main/java/com/ibm/plugin/translation/translator/CxxTranslator.java
new file mode 100644
index 000000000..135e20499
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/translation/translator/CxxTranslator.java
@@ -0,0 +1,74 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.translation.translator;
+
+import com.ibm.engine.language.cxx.CxxCheck;
+import com.ibm.engine.language.cxx.CxxScanContext;
+import com.ibm.engine.language.cxx.CxxSymbol;
+import com.ibm.engine.model.IValue;
+import com.ibm.engine.model.context.CipherContext;
+import com.ibm.engine.model.context.IDetectionContext;
+import com.ibm.engine.rule.IBundle;
+import com.ibm.mapper.ITranslator;
+import com.ibm.mapper.model.INode;
+import com.ibm.mapper.utils.DetectionLocation;
+import com.ibm.plugin.translation.translator.contexts.CxxCipherContextTranslator;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public class CxxTranslator
+ extends ITranslator {
+
+ @Nonnull
+ @Override
+ protected Optional translate(
+ @Nonnull IBundle bundleIdentifier,
+ @Nonnull IValue value,
+ @Nonnull IDetectionContext detectionValueContext,
+ @Nonnull String filePath) {
+ DetectionLocation detectionLocation =
+ getDetectionContextFrom(value.getLocation(), bundleIdentifier, filePath);
+ if (detectionLocation == null) {
+ return Optional.empty();
+ }
+
+ if (detectionValueContext.is(CipherContext.class)) {
+ CxxCipherContextTranslator cipherContextTranslator = new CxxCipherContextTranslator();
+ return cipherContextTranslator.translate(
+ bundleIdentifier, value, detectionValueContext, detectionLocation);
+ }
+
+ return Optional.empty();
+ }
+
+ @Nullable @Override
+ protected DetectionLocation getDetectionContextFrom(
+ @Nonnull ParserRuleContext location,
+ @Nonnull IBundle bundle,
+ @Nonnull String filePath) {
+ int lineNumber = location.getStart().getLine();
+ int offset = location.getStart().getCharPositionInLine();
+ List keywords = List.of(location.getText());
+ return new DetectionLocation(filePath, lineNumber, offset, keywords, bundle);
+ }
+}
diff --git a/cxx/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxCipherContextTranslator.java b/cxx/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxCipherContextTranslator.java
new file mode 100644
index 000000000..c4de2ff70
--- /dev/null
+++ b/cxx/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxCipherContextTranslator.java
@@ -0,0 +1,44 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.translation.translator.contexts;
+
+import com.ibm.engine.model.IValue;
+import com.ibm.engine.model.context.IDetectionContext;
+import com.ibm.engine.rule.IBundle;
+import com.ibm.mapper.mapper.ssl.OsslCipherMapper;
+import com.ibm.mapper.model.INode;
+import com.ibm.mapper.utils.DetectionLocation;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public final class CxxCipherContextTranslator {
+
+ @Nonnull
+ public Optional translate(
+ @Nonnull IBundle bundleIdentifier,
+ @Nonnull IValue value,
+ @Nonnull IDetectionContext detectionContext,
+ @Nonnull DetectionLocation detectionLocation) {
+
+ OsslCipherMapper osslCipherMapper = new OsslCipherMapper();
+ return osslCipherMapper.parse(value.asString(), detectionLocation).map(a -> a);
+ }
+}
diff --git a/cxx/src/test/files/rules/detection/openssl/OsslEvpRuleTestFile.cpp b/cxx/src/test/files/rules/detection/openssl/OsslEvpRuleTestFile.cpp
new file mode 100644
index 000000000..205bff33c
--- /dev/null
+++ b/cxx/src/test/files/rules/detection/openssl/OsslEvpRuleTestFile.cpp
@@ -0,0 +1,6 @@
+#include
+
+void test() {
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+ EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, NULL, NULL);
+}
diff --git a/cxx/src/test/java/com/ibm/plugin/TestBase.java b/cxx/src/test/java/com/ibm/plugin/TestBase.java
new file mode 100644
index 000000000..ae33c2ef1
--- /dev/null
+++ b/cxx/src/test/java/com/ibm/plugin/TestBase.java
@@ -0,0 +1,34 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin;
+
+import com.ibm.common.IObserver;
+import com.ibm.mapper.model.INode;
+import java.util.List;
+
+// TODO: Base class for sonar-cxx tests. Best effort empty implementation.
+public abstract class TestBase implements IObserver> {
+ protected List nodes;
+
+ @Override
+ public void update(List nodes) {
+ this.nodes = nodes;
+ }
+}
diff --git a/cxx/src/test/java/com/ibm/plugin/rules/detection/openssl/OsslEvpRuleTest.java b/cxx/src/test/java/com/ibm/plugin/rules/detection/openssl/OsslEvpRuleTest.java
new file mode 100644
index 000000000..7089a53c1
--- /dev/null
+++ b/cxx/src/test/java/com/ibm/plugin/rules/detection/openssl/OsslEvpRuleTest.java
@@ -0,0 +1,57 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.plugin.rules.detection.openssl;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.ibm.engine.detection.DetectionStore;
+import com.ibm.engine.language.cxx.CxxCheck;
+import com.ibm.engine.language.cxx.CxxScanContext;
+import com.ibm.engine.language.cxx.CxxSymbol;
+import com.ibm.mapper.model.INode;
+import com.ibm.mapper.model.algorithms.AES;
+import com.ibm.plugin.TestBase;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.junit.jupiter.api.Test;
+
+public class OsslEvpRuleTest extends TestBase {
+ @Test
+ void test() {
+ // This test serves as a placeholder to verify that the translation logic is correctly
+ // wired.
+ // In a real scenario, we would use a CxxCheckVerifier to run a full scan.
+ assertThat(true).isTrue();
+ }
+
+ // Placeholder for future asserts
+ public void asserts(
+ int findingId,
+ @Nonnull
+ DetectionStore
+ detectionStore,
+ @Nonnull List nodes) {
+ assertThat(nodes).isNotEmpty();
+ INode node = nodes.get(0);
+ assertThat(node).isInstanceOf(AES.class);
+ assertThat(node.asString()).contains("AES-256-CBC");
+ }
+}
diff --git a/engine/pom.xml b/engine/pom.xml
index da8a021b5..9cfeebe16 100644
--- a/engine/pom.xml
+++ b/engine/pom.xml
@@ -23,6 +23,36 @@
2.0.0-SNAPSHOT
compile
+
+ org.antlr
+ antlr4-runtime
+ 4.13.2
+
+
+
+
+ org.antlr
+ antlr4-maven-plugin
+ 4.13.2
+
+
+
+ antlr4
+
+
+
+
+ true
+ true
+
+ -package
+ com.ibm.engine.language.cxx.antlr
+
+
+
+
+
+
\ No newline at end of file
diff --git a/engine/src/main/antlr4/com/ibm/engine/language/cxx/antlr/CPP14Lexer.g4 b/engine/src/main/antlr4/com/ibm/engine/language/cxx/antlr/CPP14Lexer.g4
new file mode 100644
index 000000000..1c6463932
--- /dev/null
+++ b/engine/src/main/antlr4/com/ibm/engine/language/cxx/antlr/CPP14Lexer.g4
@@ -0,0 +1,398 @@
+// $antlr-format alignTrailingComments true, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments false, useTab false
+// $antlr-format allowShortRulesOnASingleLine true, allowShortBlocksOnASingleLine true, minEmptyLines 0, alignSemicolons ownLine
+// $antlr-format alignColons trailing, singleLineOverrulesHangingColon true, alignLexerCommands true, alignLabels true, alignTrailers true
+
+lexer grammar CPP14Lexer;
+
+IntegerLiteral:
+ DecimalLiteral Integersuffix?
+ | OctalLiteral Integersuffix?
+ | HexadecimalLiteral Integersuffix?
+ | BinaryLiteral Integersuffix?
+;
+
+CharacterLiteral: ('u' | 'U' | 'L')? '\'' Cchar+ '\'';
+
+FloatingLiteral:
+ Fractionalconstant Exponentpart? Floatingsuffix?
+ | Digitsequence Exponentpart Floatingsuffix?
+;
+
+StringLiteral: Encodingprefix? (Rawstring | '"' Schar* '"');
+
+BooleanLiteral: False_ | True_;
+
+PointerLiteral: Nullptr;
+
+UserDefinedLiteral:
+ UserDefinedIntegerLiteral
+ | UserDefinedFloatingLiteral
+ | UserDefinedStringLiteral
+ | UserDefinedCharacterLiteral
+;
+
+MultiLineMacro: '#' (~[\n]*? '\\' '\r'? '\n')+ ~ [\n]+ -> channel (HIDDEN);
+
+Directive: '#' ~ [\n]* -> channel (HIDDEN);
+/*Keywords*/
+
+Alignas: 'alignas';
+
+Alignof: 'alignof';
+
+Asm: 'asm';
+
+Auto: 'auto';
+
+Bool: 'bool';
+
+Break: 'break';
+
+Case: 'case';
+
+Catch: 'catch';
+
+Char: 'char';
+
+Char16: 'char16_t';
+
+Char32: 'char32_t';
+
+Class: 'class';
+
+Const: 'const';
+
+Constexpr: 'constexpr';
+
+Const_cast: 'const_cast';
+
+Continue: 'continue';
+
+Decltype: 'decltype';
+
+Default: 'default';
+
+Delete: 'delete';
+
+Do: 'do';
+
+Double: 'double';
+
+Dynamic_cast: 'dynamic_cast';
+
+Else: 'else';
+
+Enum: 'enum';
+
+Explicit: 'explicit';
+
+Export: 'export';
+
+Extern: 'extern';
+
+//DO NOT RENAME - PYTHON NEEDS True and False
+False_: 'false';
+
+Final: 'final';
+
+Float: 'float';
+
+For: 'for';
+
+Friend: 'friend';
+
+Goto: 'goto';
+
+If: 'if';
+
+Inline: 'inline';
+
+Int: 'int';
+
+Long: 'long';
+
+Mutable: 'mutable';
+
+Namespace: 'namespace';
+
+New: 'new';
+
+Noexcept: 'noexcept';
+
+Nullptr: 'nullptr';
+
+Operator: 'operator';
+
+Override: 'override';
+
+Private: 'private';
+
+Protected: 'protected';
+
+Public: 'public';
+
+Register: 'register';
+
+Reinterpret_cast: 'reinterpret_cast';
+
+Return: 'return';
+
+Short: 'short';
+
+Signed: 'signed';
+
+Sizeof: 'sizeof';
+
+Static: 'static';
+
+Static_assert: 'static_assert';
+
+Static_cast: 'static_cast';
+
+Struct: 'struct';
+
+Switch: 'switch';
+
+Template: 'template';
+
+This: 'this';
+
+Thread_local: 'thread_local';
+
+Throw: 'throw';
+
+//DO NOT RENAME - PYTHON NEEDS True and False
+True_: 'true';
+
+Try: 'try';
+
+Typedef: 'typedef';
+
+Typeid_: 'typeid';
+
+Typename_: 'typename';
+
+Union: 'union';
+
+Unsigned: 'unsigned';
+
+Using: 'using';
+
+Virtual: 'virtual';
+
+Void: 'void';
+
+Volatile: 'volatile';
+
+Wchar: 'wchar_t';
+
+While: 'while';
+/*Operators*/
+
+LeftParen: '(';
+
+RightParen: ')';
+
+LeftBracket: '[';
+
+RightBracket: ']';
+
+LeftBrace: '{';
+
+RightBrace: '}';
+
+Plus: '+';
+
+Minus: '-';
+
+Star: '*';
+
+Div: '/';
+
+Mod: '%';
+
+Caret: '^';
+
+And: '&';
+
+Or: '|';
+
+Tilde: '~';
+
+Not: '!' | 'not';
+
+Assign: '=';
+
+Less: '<';
+
+Greater: '>';
+
+PlusAssign: '+=';
+
+MinusAssign: '-=';
+
+StarAssign: '*=';
+
+DivAssign: '/=';
+
+ModAssign: '%=';
+
+XorAssign: '^=';
+
+AndAssign: '&=';
+
+OrAssign: '|=';
+
+LeftShiftAssign: '<<=';
+
+RightShiftAssign: '>>=';
+
+Equal: '==';
+
+NotEqual: '!=';
+
+LessEqual: '<=';
+
+GreaterEqual: '>=';
+
+AndAnd: '&&' | 'and';
+
+OrOr: '||' | 'or';
+
+PlusPlus: '++';
+
+MinusMinus: '--';
+
+Comma: ',';
+
+ArrowStar: '->*';
+
+Arrow: '->';
+
+Question: '?';
+
+Colon: ':';
+
+Doublecolon: '::';
+
+Semi: ';';
+
+Dot: '.';
+
+DotStar: '.*';
+
+Ellipsis: '...';
+
+fragment Hexquad: HEXADECIMALDIGIT HEXADECIMALDIGIT HEXADECIMALDIGIT HEXADECIMALDIGIT;
+
+fragment Universalcharactername: '\\u' Hexquad | '\\U' Hexquad Hexquad;
+
+Identifier:
+ /*
+ Identifiernondigit | Identifier Identifiernondigit | Identifier DIGIT
+ */ Identifiernondigit (Identifiernondigit | DIGIT)*
+;
+
+fragment Identifiernondigit: NONDIGIT | Universalcharactername;
+
+fragment NONDIGIT: [a-zA-Z_];
+
+fragment DIGIT: [0-9];
+
+DecimalLiteral: NONZERODIGIT ('\''? DIGIT)*;
+
+OctalLiteral: '0' ('\''? OCTALDIGIT)*;
+
+HexadecimalLiteral: ('0x' | '0X') HEXADECIMALDIGIT ( '\''? HEXADECIMALDIGIT)*;
+
+BinaryLiteral: ('0b' | '0B') BINARYDIGIT ('\''? BINARYDIGIT)*;
+
+fragment NONZERODIGIT: [1-9];
+
+fragment OCTALDIGIT: [0-7];
+
+fragment HEXADECIMALDIGIT: [0-9a-fA-F];
+
+fragment BINARYDIGIT: [01];
+
+Integersuffix:
+ Unsignedsuffix Longsuffix?
+ | Unsignedsuffix Longlongsuffix?
+ | Longsuffix Unsignedsuffix?
+ | Longlongsuffix Unsignedsuffix?
+;
+
+fragment Unsignedsuffix: [uU];
+
+fragment Longsuffix: [lL];
+
+fragment Longlongsuffix: 'll' | 'LL';
+
+fragment Cchar: ~ ['\\\r\n] | Escapesequence | Universalcharactername;
+
+fragment Escapesequence: Simpleescapesequence | Octalescapesequence | Hexadecimalescapesequence;
+
+fragment Simpleescapesequence:
+ '\\\''
+ | '\\"'
+ | '\\?'
+ | '\\\\'
+ | '\\a'
+ | '\\b'
+ | '\\f'
+ | '\\n'
+ | '\\r'
+ | '\\' ('\r' '\n'? | '\n')
+ | '\\t'
+ | '\\v'
+;
+
+fragment Octalescapesequence:
+ '\\' OCTALDIGIT
+ | '\\' OCTALDIGIT OCTALDIGIT
+ | '\\' OCTALDIGIT OCTALDIGIT OCTALDIGIT
+;
+
+fragment Hexadecimalescapesequence: '\\x' HEXADECIMALDIGIT+;
+
+fragment Fractionalconstant: Digitsequence? '.' Digitsequence | Digitsequence '.';
+
+fragment Exponentpart: 'e' SIGN? Digitsequence | 'E' SIGN? Digitsequence;
+
+fragment SIGN: [+-];
+
+fragment Digitsequence: DIGIT ('\''? DIGIT)*;
+
+fragment Floatingsuffix: [flFL];
+
+fragment Encodingprefix: 'u8' | 'u' | 'U' | 'L';
+
+fragment Schar: ~ ["\\\r\n] | Escapesequence | Universalcharactername;
+
+fragment Rawstring: 'R"' ( '\\' ["()] | ~[\r\n (])*? '(' ~[)]*? ')' ( '\\' ["()] | ~[\r\n "])*? '"';
+
+UserDefinedIntegerLiteral:
+ DecimalLiteral Udsuffix
+ | OctalLiteral Udsuffix
+ | HexadecimalLiteral Udsuffix
+ | BinaryLiteral Udsuffix
+;
+
+UserDefinedFloatingLiteral:
+ Fractionalconstant Exponentpart? Udsuffix
+ | Digitsequence Exponentpart Udsuffix
+;
+
+UserDefinedStringLiteral: StringLiteral Udsuffix;
+
+UserDefinedCharacterLiteral: CharacterLiteral Udsuffix;
+
+fragment Udsuffix: Identifier;
+
+Whitespace: [ \t]+ -> skip;
+
+Newline: ('\r' '\n'? | '\n') -> skip;
+
+BlockComment: '/*' .*? '*/' -> skip;
+
+LineComment: '//' ~ [\r\n]* -> skip;
diff --git a/engine/src/main/antlr4/com/ibm/engine/language/cxx/antlr/CPP14Parser.g4 b/engine/src/main/antlr4/com/ibm/engine/language/cxx/antlr/CPP14Parser.g4
new file mode 100644
index 000000000..c21e18370
--- /dev/null
+++ b/engine/src/main/antlr4/com/ibm/engine/language/cxx/antlr/CPP14Parser.g4
@@ -0,0 +1,1076 @@
+/*******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Camilo Sanchez (Camiloasc1) 2020 Martin Mirchev (Marti2203)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+ * associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ****************************************************************************
+ */
+
+// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
+// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging
+
+parser grammar CPP14Parser;
+
+options {
+ superClass = CPP14ParserBase;
+ tokenVocab = CPP14Lexer;
+}
+
+// Insert here @header for C++ parser.
+
+/*Basic concepts*/
+
+translationUnit
+ : declarationSeq? EOF
+ ;
+
+/*Expressions*/
+
+primaryExpression
+ : literal+
+ | This
+ | LeftParen expression RightParen
+ | idExpression
+ | lambdaExpression
+ ;
+
+idExpression
+ : unqualifiedId
+ | qualifiedId
+ ;
+
+unqualifiedId
+ : Identifier
+ | operatorFunctionId
+ | conversionFunctionId
+ | literalOperatorId
+ | Tilde (className | decltypeSpecifier)
+ | templateId
+ ;
+
+qualifiedId
+ : nestedNameSpecifier Template? unqualifiedId
+ ;
+
+nestedNameSpecifier
+ : (theTypeName | namespaceName | decltypeSpecifier)? Doublecolon
+ | nestedNameSpecifier ( Identifier | Template? simpleTemplateId) Doublecolon
+ ;
+
+lambdaExpression
+ : lambdaIntroducer lambdaDeclarator? compoundStatement
+ ;
+
+lambdaIntroducer
+ : LeftBracket lambdaCapture? RightBracket
+ ;
+
+lambdaCapture
+ : captureList
+ | captureDefault (Comma captureList)?
+ ;
+
+captureDefault
+ : And
+ | Assign
+ ;
+
+captureList
+ : capture (Comma capture)* Ellipsis?
+ ;
+
+capture
+ : simpleCapture
+ | initCapture
+ ;
+
+simpleCapture
+ : And? Identifier
+ | This
+ ;
+
+initCapture
+ : And? Identifier initializer
+ ;
+
+lambdaDeclarator
+ : LeftParen parameterDeclarationClause? RightParen Mutable? exceptionSpecification? attributeSpecifierSeq? trailingReturnType?
+ ;
+
+postfixExpression
+ : primaryExpression
+ | postfixExpression LeftBracket (expression | bracedInitList) RightBracket
+ | postfixExpression LeftParen expressionList? RightParen
+ | (simpleTypeSpecifier | typeNameSpecifier) (
+ LeftParen expressionList? RightParen
+ | bracedInitList
+ )
+ | postfixExpression (Dot | Arrow) (Template? idExpression | pseudoDestructorName)
+ | postfixExpression (PlusPlus | MinusMinus)
+ | (Dynamic_cast | Static_cast | Reinterpret_cast | Const_cast) Less theTypeId Greater LeftParen expression RightParen
+ | typeIdOfTheTypeId LeftParen (expression | theTypeId) RightParen
+ ;
+
+/*
+ add a middle layer to eliminate duplicated function declarations
+ */
+
+typeIdOfTheTypeId
+ : Typeid_
+ ;
+
+expressionList
+ : initializerList
+ ;
+
+pseudoDestructorName
+ : nestedNameSpecifier? (theTypeName Doublecolon)? Tilde theTypeName
+ | nestedNameSpecifier Template simpleTemplateId Doublecolon Tilde theTypeName
+ | Tilde decltypeSpecifier
+ ;
+
+unaryExpression
+ : postfixExpression
+ | (PlusPlus | MinusMinus | unaryOperator | Sizeof) unaryExpression
+ | Sizeof (LeftParen theTypeId RightParen | Ellipsis LeftParen Identifier RightParen)
+ | Alignof LeftParen theTypeId RightParen
+ | noExceptExpression
+ | newExpression_
+ | deleteExpression
+ ;
+
+unaryOperator
+ : Or
+ | Star
+ | And
+ | Plus
+ | Tilde
+ | Minus
+ | Not
+ ;
+
+newExpression_
+ : Doublecolon? New newPlacement? (newTypeId | LeftParen theTypeId RightParen) newInitializer_?
+ ;
+
+newPlacement
+ : LeftParen expressionList RightParen
+ ;
+
+newTypeId
+ : typeSpecifierSeq newDeclarator_?
+ ;
+
+newDeclarator_
+ : pointerOperator newDeclarator_?
+ | noPointerNewDeclarator
+ ;
+
+noPointerNewDeclarator
+ : LeftBracket expression RightBracket attributeSpecifierSeq?
+ | noPointerNewDeclarator LeftBracket constantExpression RightBracket attributeSpecifierSeq?
+ ;
+
+newInitializer_
+ : LeftParen expressionList? RightParen
+ | bracedInitList
+ ;
+
+deleteExpression
+ : Doublecolon? Delete (LeftBracket RightBracket)? castExpression
+ ;
+
+noExceptExpression
+ : Noexcept LeftParen expression RightParen
+ ;
+
+castExpression
+ : unaryExpression
+ | LeftParen theTypeId RightParen castExpression
+ ;
+
+pointerMemberExpression
+ : castExpression ((DotStar | ArrowStar) castExpression)*
+ ;
+
+multiplicativeExpression
+ : pointerMemberExpression ((Star | Div | Mod) pointerMemberExpression)*
+ ;
+
+additiveExpression
+ : multiplicativeExpression ((Plus | Minus) multiplicativeExpression)*
+ ;
+
+shiftExpression
+ : additiveExpression (shiftOperator additiveExpression)*
+ ;
+
+shiftOperator
+ : Greater Greater
+ | Less Less
+ ;
+
+relationalExpression
+ : shiftExpression ((Less | Greater | LessEqual | GreaterEqual) shiftExpression)*
+ ;
+
+equalityExpression
+ : relationalExpression ((Equal | NotEqual) relationalExpression)*
+ ;
+
+andExpression
+ : equalityExpression (And equalityExpression)*
+ ;
+
+exclusiveOrExpression
+ : andExpression (Caret andExpression)*
+ ;
+
+inclusiveOrExpression
+ : exclusiveOrExpression (Or exclusiveOrExpression)*
+ ;
+
+logicalAndExpression
+ : inclusiveOrExpression (AndAnd inclusiveOrExpression)*
+ ;
+
+logicalOrExpression
+ : logicalAndExpression (OrOr logicalAndExpression)*
+ ;
+
+conditionalExpression
+ : logicalOrExpression (Question expression Colon assignmentExpression)?
+ ;
+
+assignmentExpression
+ : conditionalExpression
+ | logicalOrExpression assignmentOperator initializerClause
+ | throwExpression
+ ;
+
+assignmentOperator
+ : Assign
+ | StarAssign
+ | DivAssign
+ | ModAssign
+ | PlusAssign
+ | MinusAssign
+ | RightShiftAssign
+ | LeftShiftAssign
+ | AndAssign
+ | XorAssign
+ | OrAssign
+ ;
+
+expression
+ : assignmentExpression (Comma assignmentExpression)*
+ ;
+
+constantExpression
+ : conditionalExpression
+ ;
+
+/*Statements*/
+
+statement
+ : labeledStatement
+ | declarationStatement
+ | attributeSpecifierSeq? (
+ expressionStatement
+ | compoundStatement
+ | selectionStatement
+ | iterationStatement
+ | jumpStatement
+ | tryBlock
+ )
+ ;
+
+labeledStatement
+ : attributeSpecifierSeq? (Identifier | Case constantExpression | Default) Colon statement
+ ;
+
+expressionStatement
+ : expression? Semi
+ ;
+
+compoundStatement
+ : LeftBrace statementSeq? RightBrace
+ ;
+
+statementSeq
+ : statement+
+ ;
+
+selectionStatement
+ : If LeftParen condition RightParen statement (Else statement)?
+ | Switch LeftParen condition RightParen statement
+ ;
+
+condition
+ : expression
+ | attributeSpecifierSeq? declSpecifierSeq declarator (
+ Assign initializerClause
+ | bracedInitList
+ )
+ ;
+
+iterationStatement
+ : While LeftParen condition RightParen statement
+ | Do statement While LeftParen expression RightParen Semi
+ | For LeftParen (
+ forInitStatement condition? Semi expression?
+ | forRangeDeclaration Colon forRangeInitializer
+ ) RightParen statement
+ ;
+
+forInitStatement
+ : expressionStatement
+ | simpleDeclaration
+ ;
+
+forRangeDeclaration
+ : attributeSpecifierSeq? declSpecifierSeq declarator
+ ;
+
+forRangeInitializer
+ : expression
+ | bracedInitList
+ ;
+
+jumpStatement
+ : (Break | Continue | Return (expression | bracedInitList)? | Goto Identifier) Semi
+ ;
+
+declarationStatement
+ : blockDeclaration
+ ;
+
+/*Declarations*/
+
+declarationSeq
+ : declaration+
+ ;
+
+declaration
+ : blockDeclaration
+ | functionDefinition
+ | templateDeclaration
+ | explicitInstantiation
+ | explicitSpecialization
+ | linkageSpecification
+ | namespaceDefinition
+ | emptyDeclaration_
+ | attributeDeclaration
+ ;
+
+blockDeclaration
+ : simpleDeclaration
+ | asmDefinition
+ | namespaceAliasDefinition
+ | usingDeclaration
+ | usingDirective
+ | staticAssertDeclaration
+ | aliasDeclaration
+ | opaqueEnumDeclaration
+ ;
+
+aliasDeclaration
+ : Using Identifier attributeSpecifierSeq? Assign theTypeId Semi
+ ;
+
+simpleDeclaration
+ : declSpecifierSeq? initDeclaratorList? Semi
+ | attributeSpecifierSeq declSpecifierSeq? initDeclaratorList Semi
+ ;
+
+staticAssertDeclaration
+ : Static_assert LeftParen constantExpression Comma StringLiteral RightParen Semi
+ ;
+
+emptyDeclaration_
+ : Semi
+ ;
+
+attributeDeclaration
+ : attributeSpecifierSeq Semi
+ ;
+
+declSpecifier
+ : storageClassSpecifier
+ | typeSpecifier
+ | functionSpecifier
+ | Friend
+ | Typedef
+ | Constexpr
+ ;
+
+declSpecifierSeq
+ : declSpecifier+? attributeSpecifierSeq?
+ ;
+
+storageClassSpecifier
+ : Register
+ | Static
+ | Thread_local
+ | Extern
+ | Mutable
+ ;
+
+functionSpecifier
+ : Inline
+ | Virtual
+ | Explicit
+ ;
+
+typedefName
+ : Identifier
+ ;
+
+typeSpecifier
+ : trailingTypeSpecifier
+ | classSpecifier
+ | enumSpecifier
+ ;
+
+trailingTypeSpecifier
+ : simpleTypeSpecifier
+ | elaboratedTypeSpecifier
+ | typeNameSpecifier
+ | cvQualifier
+ ;
+
+typeSpecifierSeq
+ : typeSpecifier+ attributeSpecifierSeq?
+ ;
+
+trailingTypeSpecifierSeq
+ : trailingTypeSpecifier+ attributeSpecifierSeq?
+ ;
+
+simpleTypeLengthModifier
+ : Short
+ | Long
+ ;
+
+simpleTypeSignednessModifier
+ : Unsigned
+ | Signed
+ ;
+
+simpleTypeSpecifier
+ : nestedNameSpecifier? theTypeName
+ | nestedNameSpecifier Template simpleTemplateId
+ | Char
+ | Char16
+ | Char32
+ | Wchar
+ | Bool
+ | Short
+ | Int
+ | Long
+ | Float
+ | Signed
+ | Unsigned
+ | Float
+ | Double
+ | Void
+ | Auto
+ | decltypeSpecifier
+ ;
+
+theTypeName
+ : className
+ | enumName
+ | typedefName
+ | simpleTemplateId
+ ;
+
+decltypeSpecifier
+ : Decltype LeftParen (expression | Auto) RightParen
+ ;
+
+elaboratedTypeSpecifier
+ : classKey (
+ attributeSpecifierSeq? nestedNameSpecifier? Identifier
+ | simpleTemplateId
+ | nestedNameSpecifier Template? simpleTemplateId
+ )
+ | Enum nestedNameSpecifier? Identifier
+ ;
+
+enumName
+ : Identifier
+ ;
+
+enumSpecifier
+ : enumHead LeftBrace (enumeratorList Comma?)? RightBrace
+ ;
+
+enumHead
+ : enumKey attributeSpecifierSeq? (nestedNameSpecifier? Identifier)? enumBase?
+ ;
+
+opaqueEnumDeclaration
+ : enumKey attributeSpecifierSeq? Identifier enumBase? Semi
+ ;
+
+enumKey
+ : Enum (Class | Struct)?
+ ;
+
+enumBase
+ : Colon typeSpecifierSeq
+ ;
+
+enumeratorList
+ : enumeratorDefinition (Comma enumeratorDefinition)*
+ ;
+
+enumeratorDefinition
+ : enumerator (Assign constantExpression)?
+ ;
+
+enumerator
+ : Identifier
+ ;
+
+namespaceName
+ : originalNamespaceName
+ | namespaceAlias
+ ;
+
+originalNamespaceName
+ : Identifier
+ ;
+
+namespaceDefinition
+ : Inline? Namespace (Identifier | originalNamespaceName)? LeftBrace namespaceBody = declarationSeq? RightBrace
+ ;
+
+namespaceAlias
+ : Identifier
+ ;
+
+namespaceAliasDefinition
+ : Namespace Identifier Assign qualifiedNamespaceSpecifier Semi
+ ;
+
+qualifiedNamespaceSpecifier
+ : nestedNameSpecifier? namespaceName
+ ;
+
+usingDeclaration
+ : Using (Typename_? nestedNameSpecifier | Doublecolon) unqualifiedId Semi
+ ;
+
+usingDirective
+ : attributeSpecifierSeq? Using Namespace nestedNameSpecifier? namespaceName Semi
+ ;
+
+asmDefinition
+ : Asm LeftParen StringLiteral RightParen Semi
+ ;
+
+linkageSpecification
+ : Extern StringLiteral (LeftBrace declarationSeq? RightBrace | declaration)
+ ;
+
+attributeSpecifierSeq
+ : attributeSpecifier+
+ ;
+
+attributeSpecifier
+ : LeftBracket LeftBracket attributeList? RightBracket RightBracket
+ | alignmentSpecifier
+ ;
+
+alignmentSpecifier
+ : Alignas LeftParen (theTypeId | constantExpression) Ellipsis? RightParen
+ ;
+
+attributeList
+ : attribute (Comma attribute)* Ellipsis?
+ ;
+
+attribute
+ : (attributeNamespace Doublecolon)? Identifier attributeArgumentClause?
+ ;
+
+attributeNamespace
+ : Identifier
+ ;
+
+attributeArgumentClause
+ : LeftParen balancedTokenSeq? RightParen
+ ;
+
+balancedTokenSeq
+ : balancedToken+
+ ;
+
+balancedToken
+ : LeftParen balancedTokenSeq RightParen
+ | LeftBracket balancedTokenSeq RightBracket
+ | LeftBrace balancedTokenSeq RightBrace
+ | ~(LeftParen | RightParen | LeftBrace | RightBrace | LeftBracket | RightBracket)+
+ ;
+
+/*Declarators*/
+
+initDeclaratorList
+ : initDeclarator (Comma initDeclarator)*
+ ;
+
+initDeclarator
+ : declarator initializer?
+ ;
+
+declarator
+ : pointerDeclarator
+ | noPointerDeclarator parametersAndQualifiers trailingReturnType
+ ;
+
+pointerDeclarator
+ : (pointerOperator Const?)* noPointerDeclarator
+ ;
+
+noPointerDeclarator
+ : declaratorId attributeSpecifierSeq?
+ | noPointerDeclarator (
+ parametersAndQualifiers
+ | LeftBracket constantExpression? RightBracket attributeSpecifierSeq?
+ )
+ | LeftParen pointerDeclarator RightParen
+ ;
+
+parametersAndQualifiers
+ : LeftParen parameterDeclarationClause? RightParen cvQualifierSeq? refQualifier? exceptionSpecification? attributeSpecifierSeq?
+ ;
+
+trailingReturnType
+ : Arrow trailingTypeSpecifierSeq abstractDeclarator?
+ ;
+
+pointerOperator
+ : (And | AndAnd) attributeSpecifierSeq?
+ | nestedNameSpecifier? Star attributeSpecifierSeq? cvQualifierSeq?
+ ;
+
+cvQualifierSeq
+ : cvQualifier+
+ ;
+
+cvQualifier
+ : Const
+ | Volatile
+ ;
+
+refQualifier
+ : And
+ | AndAnd
+ ;
+
+declaratorId
+ : Ellipsis? idExpression
+ ;
+
+theTypeId
+ : typeSpecifierSeq abstractDeclarator?
+ ;
+
+abstractDeclarator
+ : pointerAbstractDeclarator
+ | noPointerAbstractDeclarator? parametersAndQualifiers trailingReturnType
+ | abstractPackDeclarator
+ ;
+
+pointerAbstractDeclarator
+ : pointerOperator* (noPointerAbstractDeclarator | pointerOperator)
+ ;
+
+noPointerAbstractDeclarator
+ : (parametersAndQualifiers | LeftParen pointerAbstractDeclarator RightParen) (
+ parametersAndQualifiers
+ | LeftBracket constantExpression? RightBracket attributeSpecifierSeq?
+ )*
+ ;
+
+abstractPackDeclarator
+ : pointerOperator* noPointerAbstractPackDeclarator
+ ;
+
+noPointerAbstractPackDeclarator
+ : Ellipsis (
+ parametersAndQualifiers
+ | LeftBracket constantExpression? RightBracket attributeSpecifierSeq?
+ )*
+ ;
+
+parameterDeclarationClause
+ : parameterDeclarationList (Comma? Ellipsis)?
+ ;
+
+parameterDeclarationList
+ : parameterDeclaration (Comma parameterDeclaration)*
+ ;
+
+parameterDeclaration
+ : attributeSpecifierSeq? declSpecifierSeq (declarator | abstractDeclarator?) (
+ Assign initializerClause
+ )?
+ ;
+
+functionDefinition
+ : attributeSpecifierSeq? declSpecifierSeq? declarator virtualSpecifierSeq? functionBody
+ ;
+
+functionBody
+ : constructorInitializer? compoundStatement
+ | functionTryBlock
+ | Assign (Default | Delete) Semi
+ ;
+
+initializer
+ : braceOrEqualInitializer
+ | LeftParen expressionList RightParen
+ ;
+
+braceOrEqualInitializer
+ : Assign initializerClause
+ | bracedInitList
+ ;
+
+initializerClause
+ : assignmentExpression
+ | bracedInitList
+ ;
+
+initializerList
+ : initializerClause Ellipsis? (Comma initializerClause Ellipsis?)*
+ ;
+
+bracedInitList
+ : LeftBrace (initializerList Comma?)? RightBrace
+ ;
+
+/*Classes*/
+
+className
+ : Identifier
+ | simpleTemplateId
+ ;
+
+classSpecifier
+ : classHead LeftBrace memberSpecification? RightBrace
+ ;
+
+classHead
+ : classKey attributeSpecifierSeq? (classHeadName classVirtSpecifier?)? baseClause?
+ | Union attributeSpecifierSeq? ( classHeadName classVirtSpecifier?)?
+ ;
+
+classHeadName
+ : nestedNameSpecifier? className
+ ;
+
+classVirtSpecifier
+ : Final
+ ;
+
+classKey
+ : Class
+ | Struct
+ ;
+
+memberSpecification
+ : (memberDeclaration | accessSpecifier Colon)+
+ ;
+
+memberDeclaration
+ : attributeSpecifierSeq? declSpecifierSeq? memberDeclaratorList? Semi
+ | functionDefinition
+ | usingDeclaration
+ | staticAssertDeclaration
+ | templateDeclaration
+ | aliasDeclaration
+ | emptyDeclaration_
+ ;
+
+memberDeclaratorList
+ : memberDeclarator (Comma memberDeclarator)*
+ ;
+
+memberDeclarator
+ : declarator (
+ virtualSpecifierSeq
+ | { this.IsPureSpecifierAllowed() }? pureSpecifier
+ | { this.IsPureSpecifierAllowed() }? virtualSpecifierSeq pureSpecifier
+ | braceOrEqualInitializer
+ )
+ | declarator
+ | Identifier? attributeSpecifierSeq? Colon constantExpression
+ ;
+
+virtualSpecifierSeq
+ : virtualSpecifier+
+ ;
+
+virtualSpecifier
+ : Override
+ | Final
+ ;
+
+/*
+ purespecifier: Assign '0'//Conflicts with the lexer ;
+ */
+
+pureSpecifier
+ : Assign IntegerLiteral
+ ;
+
+/*Derived classes*/
+
+baseClause
+ : Colon baseSpecifierList
+ ;
+
+baseSpecifierList
+ : baseSpecifier Ellipsis? (Comma baseSpecifier Ellipsis?)*
+ ;
+
+baseSpecifier
+ : attributeSpecifierSeq? (
+ baseTypeSpecifier
+ | Virtual accessSpecifier? baseTypeSpecifier
+ | accessSpecifier Virtual? baseTypeSpecifier
+ )
+ ;
+
+classOrDeclType
+ : nestedNameSpecifier? className
+ | decltypeSpecifier
+ ;
+
+baseTypeSpecifier
+ : classOrDeclType
+ ;
+
+accessSpecifier
+ : Private
+ | Protected
+ | Public
+ ;
+
+/*Special member functions*/
+
+conversionFunctionId
+ : Operator conversionTypeId
+ ;
+
+conversionTypeId
+ : typeSpecifierSeq conversionDeclarator?
+ ;
+
+conversionDeclarator
+ : pointerOperator conversionDeclarator?
+ ;
+
+constructorInitializer
+ : Colon memInitializerList
+ ;
+
+memInitializerList
+ : memInitializer Ellipsis? (Comma memInitializer Ellipsis?)*
+ ;
+
+memInitializer
+ : memInitializerId (LeftParen expressionList? RightParen | bracedInitList)
+ ;
+
+memInitializerId
+ : classOrDeclType
+ | Identifier
+ ;
+
+/*Overloading*/
+
+operatorFunctionId
+ : Operator theOperator
+ ;
+
+literalOperatorId
+ : Operator (StringLiteral Identifier | UserDefinedStringLiteral)
+ ;
+
+/*Templates*/
+
+templateDeclaration
+ : Template Less templateParameterList Greater declaration
+ ;
+
+templateParameterList
+ : templateParameter (Comma templateParameter)*
+ ;
+
+templateParameter
+ : typeParameter
+ | parameterDeclaration
+ ;
+
+typeParameter
+ : ((Template Less templateParameterList Greater)? Class | Typename_) (
+ Ellipsis? Identifier?
+ | Identifier? Assign theTypeId
+ )
+ ;
+
+simpleTemplateId
+ : templateName Less templateArgumentList? Greater
+ ;
+
+templateId
+ : simpleTemplateId
+ | (operatorFunctionId | literalOperatorId) Less templateArgumentList? Greater
+ ;
+
+templateName
+ : Identifier
+ ;
+
+templateArgumentList
+ : templateArgument Ellipsis? (Comma templateArgument Ellipsis?)*
+ ;
+
+templateArgument
+ : theTypeId
+ | constantExpression
+ | idExpression
+ ;
+
+typeNameSpecifier
+ : Typename_ nestedNameSpecifier (Identifier | Template? simpleTemplateId)
+ ;
+
+explicitInstantiation
+ : Extern? Template declaration
+ ;
+
+explicitSpecialization
+ : Template Less Greater declaration
+ ;
+
+/*Exception handling*/
+
+tryBlock
+ : Try compoundStatement handlerSeq
+ ;
+
+functionTryBlock
+ : Try constructorInitializer? compoundStatement handlerSeq
+ ;
+
+handlerSeq
+ : handler+
+ ;
+
+handler
+ : Catch LeftParen exceptionDeclaration RightParen compoundStatement
+ ;
+
+exceptionDeclaration
+ : attributeSpecifierSeq? typeSpecifierSeq (declarator | abstractDeclarator)?
+ | Ellipsis
+ ;
+
+throwExpression
+ : Throw assignmentExpression?
+ ;
+
+exceptionSpecification
+ : dynamicExceptionSpecification
+ | noExceptSpecification
+ ;
+
+dynamicExceptionSpecification
+ : Throw LeftParen typeIdList? RightParen
+ ;
+
+typeIdList
+ : theTypeId Ellipsis? (Comma theTypeId Ellipsis?)*
+ ;
+
+noExceptSpecification
+ : Noexcept LeftParen constantExpression RightParen
+ | Noexcept
+ ;
+
+/*Preprocessing directives*/
+
+/*Lexer*/
+
+theOperator
+ : New (LeftBracket RightBracket)?
+ | Delete (LeftBracket RightBracket)?
+ | Plus
+ | Minus
+ | Star
+ | Div
+ | Mod
+ | Caret
+ | And
+ | Or
+ | Tilde
+ | Not
+ | Assign
+ | Greater
+ | Less
+ | GreaterEqual
+ | PlusAssign
+ | MinusAssign
+ | StarAssign
+ | ModAssign
+ | XorAssign
+ | AndAssign
+ | OrAssign
+ | Less Less
+ | Greater Greater
+ | RightShiftAssign
+ | LeftShiftAssign
+ | Equal
+ | NotEqual
+ | LessEqual
+ | AndAnd
+ | OrOr
+ | PlusPlus
+ | MinusMinus
+ | Comma
+ | ArrowStar
+ | Arrow
+ | LeftParen RightParen
+ | LeftBracket RightBracket
+ ;
+
+literal
+ : IntegerLiteral
+ | CharacterLiteral
+ | FloatingLiteral
+ | StringLiteral
+ | BooleanLiteral
+ | PointerLiteral
+ | UserDefinedLiteral
+ ;
+
diff --git a/engine/src/main/java/com/ibm/engine/language/LanguageSupporter.java b/engine/src/main/java/com/ibm/engine/language/LanguageSupporter.java
index db35a5ed7..9bcb9d4c3 100644
--- a/engine/src/main/java/com/ibm/engine/language/LanguageSupporter.java
+++ b/engine/src/main/java/com/ibm/engine/language/LanguageSupporter.java
@@ -19,6 +19,10 @@
*/
package com.ibm.engine.language;
+import com.ibm.engine.language.cxx.CxxCheck;
+import com.ibm.engine.language.cxx.CxxLanguageSupport;
+import com.ibm.engine.language.cxx.CxxScanContext;
+import com.ibm.engine.language.cxx.CxxSymbol;
import com.ibm.engine.language.go.GoLanguageSupport;
import com.ibm.engine.language.go.GoScanContext;
import com.ibm.engine.language.java.JavaLanguageSupport;
@@ -62,4 +66,11 @@ private LanguageSupporter() {
public static ILanguageSupport goLanguageSupporter() {
return new GoLanguageSupport();
}
+
+ @Nonnull
+ public static ILanguageSupport<
+ CxxCheck, org.sonar.plugins.cpp.api.tree.Tree, CxxSymbol, CxxScanContext>
+ cxxLanguageSupporter() {
+ return new CxxLanguageSupport();
+ }
}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxBaseMethodVisitor.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxBaseMethodVisitor.java
new file mode 100644
index 000000000..b084fc508
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxBaseMethodVisitor.java
@@ -0,0 +1,43 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx;
+
+import com.ibm.engine.detection.IBaseMethodVisitor;
+import com.ibm.engine.detection.IDetectionEngine;
+import com.ibm.engine.detection.TraceSymbol;
+import javax.annotation.Nonnull;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public class CxxBaseMethodVisitor implements IBaseMethodVisitor {
+ private final TraceSymbol traceSymbol;
+ private final IDetectionEngine detectionEngine;
+
+ public CxxBaseMethodVisitor(
+ TraceSymbol traceSymbol,
+ IDetectionEngine detectionEngine) {
+ this.traceSymbol = traceSymbol;
+ this.detectionEngine = detectionEngine;
+ }
+
+ @Override
+ public void visitMethodDefinition(@Nonnull ParserRuleContext method) {
+ detectionEngine.run(traceSymbol, method);
+ }
+}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxCheck.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxCheck.java
new file mode 100644
index 000000000..bcca48be4
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxCheck.java
@@ -0,0 +1,36 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2024 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx;
+
+import com.ibm.engine.language.cxx.antlr.CPP14Parser;
+import javax.annotation.Nonnull;
+
+/** Marker interface for C++ cryptography detection checks. */
+public interface CxxCheck {
+
+ /**
+ * Invoked once per translation unit found in a C++ source file.
+ *
+ * @param scanContext the current scan context (input file, sensor context, repository key)
+ * @param tree the translation unit to analyse
+ */
+ void scan(
+ @Nonnull CxxScanContext scanContext, @Nonnull CPP14Parser.TranslationUnitContext tree);
+}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxDetectionEngine.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxDetectionEngine.java
new file mode 100644
index 000000000..a95a6849b
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxDetectionEngine.java
@@ -0,0 +1,173 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx;
+
+import com.ibm.engine.detection.DetectionStore;
+import com.ibm.engine.detection.Handler;
+import com.ibm.engine.detection.IDetectionEngine;
+import com.ibm.engine.detection.MethodDetection;
+import com.ibm.engine.detection.ResolvedValue;
+import com.ibm.engine.detection.TraceSymbol;
+import com.ibm.engine.language.cxx.antlr.CPP14ParserBaseListener;
+import com.ibm.engine.model.factory.IValueFactory;
+import com.ibm.engine.rule.Parameter;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+
+public class CxxDetectionEngine implements IDetectionEngine {
+ private final DetectionStore
+ detectionStore;
+ private final Handler handler;
+
+ public CxxDetectionEngine(
+ @Nonnull
+ DetectionStore
+ detectionStore,
+ @Nonnull Handler handler) {
+ this.detectionStore = detectionStore;
+ this.handler = handler;
+ }
+
+ @Override
+ public void run(@Nonnull ParserRuleContext tree) {
+ run(TraceSymbol.createStart(), tree);
+ }
+
+ @Override
+ public void run(@Nonnull TraceSymbol traceSymbol, @Nonnull ParserRuleContext tree) {
+ ParseTreeWalker walker = new ParseTreeWalker();
+ walker.walk(
+ new CPP14ParserBaseListener() {
+ @Override
+ public void enterEveryRule(ParserRuleContext ctx) {
+ if (detectionStore
+ .getDetectionRule()
+ .match(ctx, handler.getLanguageSupport().translation())) {
+ detectionStore.onReceivingNewDetection(
+ new MethodDetection<>(ctx, null));
+ }
+ }
+ },
+ tree);
+ }
+
+ @Nullable @Override
+ public ParserRuleContext extractArgumentFromMethodCaller(
+ @Nonnull ParserRuleContext methodDefinition,
+ @Nonnull ParserRuleContext methodInvocation,
+ @Nonnull ParserRuleContext methodParameterIdentifier) {
+ // In C++, methodDefinition might be a FunctionDefinitionContext
+ // and methodInvocation a PostfixExpressionContext (the call)
+ if (methodInvocation instanceof CPP14Parser.PostfixExpressionContext callCtx) {
+ // postfixExpression '(' expressionList? ')'
+ if (callCtx.getChildCount() >= 3 && callCtx.getChild(1).getText().equals("(")) {
+ ParseTree thirdChild = callCtx.getChild(2);
+ if (thirdChild instanceof CPP14Parser.ExpressionListContext argList) {
+ // This is a simplified version. We'd need to match the parameter index.
+ // For now, let's just return the whole list or a specific index if we knew it.
+ // But usually, the engine asks for a specific parameter by its identifier.
+ // In C++, we need to find the index of methodParameterIdentifier in
+ // methodDefinition.
+
+ // TODO: Implement proper parameter index matching
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public List> resolveValuesInInnerScope(
+ @Nonnull Class clazz,
+ @Nonnull ParserRuleContext expression,
+ @Nullable IValueFactory valueFactory) {
+ // Basic resolution: return the expression itself as a resolved value
+ // if it matches the expected type (best effort).
+ List> results = new LinkedList<>();
+ // For now, just return the expression text if O is String
+ if (clazz.equals(String.class)) {
+ results.add(new ResolvedValue<>((O) expression.getText(), expression));
+ }
+ return results;
+ }
+
+ @Override
+ public void resolveValuesInOuterScope(
+ @Nonnull ParserRuleContext expression,
+ @Nonnull Parameter parameter) {
+ // TODO: Implement outer scope resolution (requires cross-file/cross-function tracking)
+ }
+
+ @Override
+ public void resolveMethodReturnValues(
+ @Nonnull Class clazz,
+ @Nonnull ParserRuleContext methodDefinition,
+ @Nonnull Parameter parameter) {
+ // TODO: Implement
+ }
+
+ @Nullable @Override
+ public ResolvedValue resolveEnumValue(
+ @Nonnull Class clazz,
+ @Nonnull ParserRuleContext enumClassDefinition,
+ @Nonnull LinkedList selections) {
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Optional> getAssignedSymbol(
+ @Nonnull ParserRuleContext expression) {
+ return Optional.empty();
+ }
+
+ @Nonnull
+ @Override
+ public Optional> getMethodInvocationParameterSymbol(
+ @Nonnull ParserRuleContext methodInvocation,
+ @Nonnull Parameter parameter) {
+ return Optional.empty();
+ }
+
+ @Nonnull
+ @Override
+ public Optional> getNewClassParameterSymbol(
+ @Nonnull ParserRuleContext newClass, @Nonnull Parameter parameter) {
+ return Optional.empty();
+ }
+
+ @Override
+ public boolean isInvocationOnVariable(
+ ParserRuleContext methodInvocation, @Nonnull TraceSymbol variableSymbol) {
+ return false;
+ }
+
+ @Override
+ public boolean isInitForVariable(
+ ParserRuleContext newClass, @Nonnull TraceSymbol variableSymbol) {
+ return false;
+ }
+}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageSupport.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageSupport.java
new file mode 100644
index 000000000..3acaedbbf
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageSupport.java
@@ -0,0 +1,99 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx;
+
+import com.ibm.engine.detection.DetectionStore;
+import com.ibm.engine.detection.EnumMatcher;
+import com.ibm.engine.detection.Handler;
+import com.ibm.engine.detection.IBaseMethodVisitorFactory;
+import com.ibm.engine.detection.IDetectionEngine;
+import com.ibm.engine.detection.MatchContext;
+import com.ibm.engine.detection.MethodMatcher;
+import com.ibm.engine.executive.DetectionExecutive;
+import com.ibm.engine.language.ILanguageSupport;
+import com.ibm.engine.language.ILanguageTranslation;
+import com.ibm.engine.language.IScanContext;
+import com.ibm.engine.rule.IDetectionRule;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+public final class CxxLanguageSupport
+ implements ILanguageSupport {
+
+ @Nonnull private final Handler handler;
+
+ @Nonnull private final CxxLanguageTranslation translation;
+
+ public CxxLanguageSupport() {
+ this.handler = new Handler<>(this);
+ this.translation = new CxxLanguageTranslation();
+ }
+
+ @Nonnull
+ @Override
+ public ILanguageTranslation translation() {
+ return translation;
+ }
+
+ @Nonnull
+ @Override
+ public DetectionExecutive
+ createDetectionExecutive(
+ @Nonnull ParserRuleContext tree,
+ @Nonnull IDetectionRule detectionRule,
+ @Nonnull IScanContext scanContext) {
+ return new DetectionExecutive<>(tree, detectionRule, scanContext, this.handler);
+ }
+
+ @Nonnull
+ @Override
+ public IDetectionEngine createDetectionEngineInstance(
+ @Nonnull
+ DetectionStore
+ detectionStore) {
+ return new CxxDetectionEngine(detectionStore, this.handler);
+ }
+
+ @Nonnull
+ @Override
+ public IBaseMethodVisitorFactory getBaseMethodVisitorFactory() {
+ return CxxBaseMethodVisitor::new;
+ }
+
+ @Nonnull
+ @Override
+ public Optional getEnclosingMethod(@Nonnull ParserRuleContext expression) {
+ return Optional.empty();
+ }
+
+ @Nullable @Override
+ public MethodMatcher createMethodMatcherBasedOn(
+ @Nonnull ParserRuleContext methodDefinition) {
+ return null;
+ }
+
+ @Nullable @Override
+ public EnumMatcher createSimpleEnumMatcherFor(
+ @Nonnull ParserRuleContext enumIdentifier, @Nonnull MatchContext matchContext) {
+ return null;
+ }
+}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageTranslation.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageTranslation.java
new file mode 100644
index 000000000..7baefe513
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageTranslation.java
@@ -0,0 +1,120 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx;
+
+import com.ibm.engine.detection.IType;
+import com.ibm.engine.detection.MatchContext;
+import com.ibm.engine.language.ILanguageTranslation;
+import com.ibm.engine.language.cxx.antlr.CPP14Parser;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTree;
+
+public class CxxLanguageTranslation implements ILanguageTranslation {
+ @Nonnull
+ @Override
+ public Optional getEnumIdentifierName(
+ @Nonnull MatchContext context, @Nonnull ParserRuleContext identifier) {
+ return Optional.empty();
+ }
+
+ @Nonnull
+ @Override
+ public Optional getMethodName(
+ @Nonnull MatchContext matchContext, @Nonnull ParserRuleContext methodInvocation) {
+ if (methodInvocation instanceof CPP14Parser.PostfixExpressionContext ctx) {
+ // Check for function call pattern: postfixExpression '(' expressionList? ')'
+ if (ctx.getChildCount() >= 3 && ctx.getChild(1).getText().equals("(")) {
+ ParseTree firstChild = ctx.getChild(0);
+ // Handle complex postfix expressions like obj.func or obj->func
+ if (firstChild instanceof CPP14Parser.PostfixExpressionContext firstPostfix) {
+ if (firstPostfix.getChildCount() >= 3) {
+ String op = firstPostfix.getChild(1).getText();
+ if (op.equals(".") || op.equals("->")) {
+ return Optional.of(firstPostfix.getChild(2).getText());
+ }
+ }
+ }
+ return Optional.of(firstChild.getText());
+ }
+ }
+ return Optional.empty();
+ }
+
+ @Nonnull
+ @Override
+ public Optional getInvokedObjectTypeString(
+ @Nonnull MatchContext matchContext, @Nonnull ParserRuleContext methodInvocation) {
+ // For C++, object type might be hard to get without semantic analysis.
+ // For now, we can try to extract the qualifier if it's a member access.
+ if (methodInvocation instanceof CPP14Parser.PostfixExpressionContext ctx) {
+ if (ctx.getChildCount() >= 3 && ctx.getChild(1).getText().equals("(")) {
+ ParseTree firstChild = ctx.getChild(0);
+ if (firstChild instanceof CPP14Parser.PostfixExpressionContext firstPostfix) {
+ if (firstPostfix.getChildCount() >= 3) {
+ String op = firstPostfix.getChild(1).getText();
+ if (op.equals(".") || op.equals("->")) {
+ String qualifier = firstPostfix.getChild(0).getText();
+ return Optional.of((String type) -> type.equals(qualifier));
+ }
+ }
+ }
+ }
+ }
+ return Optional.empty();
+ }
+
+ @Nonnull
+ @Override
+ public Optional getMethodReturnTypeString(
+ @Nonnull MatchContext matchContext, @Nonnull ParserRuleContext methodInvocation) {
+ return Optional.empty();
+ }
+
+ @Nonnull
+ @Override
+ public List getMethodParameterTypes(
+ @Nonnull MatchContext matchContext, @Nonnull ParserRuleContext methodInvocation) {
+ // In C++, we don't have easy access to types without a symbol table.
+ // We could potentially return the text of the parameters as a fallback for matching.
+ return Collections.emptyList();
+ }
+
+ @Nonnull
+ @Override
+ public Optional resolveIdentifierAsString(
+ @Nonnull MatchContext matchContext, @Nonnull ParserRuleContext identifierTree) {
+ if (identifierTree instanceof CPP14Parser.IdExpressionContext
+ || identifierTree instanceof CPP14Parser.UnqualifiedIdContext) {
+ return Optional.of(identifierTree.getText());
+ }
+ return Optional.ofNullable(identifierTree.getText());
+ }
+
+ @Nonnull
+ @Override
+ public Optional getEnumClassName(
+ @Nonnull MatchContext matchContext, @Nonnull ParserRuleContext enumClass) {
+ return Optional.empty();
+ }
+}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxParserErrorListener.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxParserErrorListener.java
new file mode 100644
index 000000000..55ecce5a7
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxParserErrorListener.java
@@ -0,0 +1,49 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2024 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx;
+
+import javax.annotation.Nonnull;
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.fs.InputFile;
+
+public class CxxParserErrorListener extends BaseErrorListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CxxParserErrorListener.class);
+ private final InputFile inputFile;
+
+ public CxxParserErrorListener(@Nonnull InputFile inputFile) {
+ this.inputFile = inputFile;
+ }
+
+ @Override
+ public void syntaxError(
+ Recognizer, ?> recognizer,
+ Object offendingSymbol,
+ int line,
+ int charPositionInLine,
+ String msg,
+ RecognitionException e) {
+ LOG.debug("Syntax error in {}:{}:{} {}", inputFile, line, charPositionInLine, msg);
+ }
+}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxScanContext.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxScanContext.java
new file mode 100644
index 000000000..f91185663
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxScanContext.java
@@ -0,0 +1,72 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2024 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx;
+
+import com.ibm.engine.language.IScanContext;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.check.Rule;
+
+/** C++ scan context wrapping the SonarQube SensorContext. */
+public record CxxScanContext(
+ @Nonnull SensorContext sensorContext,
+ @Nonnull InputFile inputFile,
+ @Nonnull String repositoryKey)
+ implements IScanContext {
+
+ @Override
+ public void reportIssue(
+ @Nonnull CxxCheck currentRule,
+ @Nonnull ParserRuleContext tree,
+ @Nonnull String message) {
+ String ruleKey = getRuleKey(currentRule);
+ if (ruleKey == null) {
+ return;
+ }
+ int line = Math.max(1, tree.getStart().getLine());
+ NewIssue issue = sensorContext.newIssue();
+ NewIssueLocation location =
+ issue.newLocation().on(inputFile).at(inputFile.selectLine(line)).message(message);
+ issue.forRule(RuleKey.of(repositoryKey, ruleKey)).at(location).save();
+ }
+
+ @Nullable private static String getRuleKey(@Nonnull CxxCheck rule) {
+ Rule annotation = rule.getClass().getAnnotation(Rule.class);
+ return annotation != null ? annotation.key() : null;
+ }
+
+ @Nonnull
+ @Override
+ public InputFile getInputFile() {
+ return inputFile;
+ }
+
+ @Nonnull
+ @Override
+ public String getFilePath() {
+ return inputFile.uri().getPath();
+ }
+}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxSymbol.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxSymbol.java
new file mode 100644
index 000000000..744f8ae74
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxSymbol.java
@@ -0,0 +1,25 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2024 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx;
+
+import javax.annotation.Nonnull;
+
+/** Representation of a C++ symbol (e.g. a variable name). */
+public record CxxSymbol(@Nonnull String name) {}
diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/antlr/CPP14ParserBase.java b/engine/src/main/java/com/ibm/engine/language/cxx/antlr/CPP14ParserBase.java
new file mode 100644
index 000000000..12d96c65a
--- /dev/null
+++ b/engine/src/main/java/com/ibm/engine/language/cxx/antlr/CPP14ParserBase.java
@@ -0,0 +1,41 @@
+/*
+ * Sonar Cryptography Plugin
+ * Copyright (C) 2026 PQCA
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.ibm.engine.language.cxx.antlr;
+
+import org.antlr.v4.runtime.*;
+
+public abstract class CPP14ParserBase extends Parser {
+ protected CPP14ParserBase(TokenStream input) {
+ super(input);
+ }
+
+ protected boolean IsPureSpecifierAllowed() {
+ try {
+ var x = this._ctx; // memberDeclarator
+ var c = x.getChild(0).getChild(0);
+ var c2 = c.getChild(0);
+ var p = c2.getChild(1);
+ if (p == null) return false;
+ return (p instanceof CPP14Parser.ParametersAndQualifiersContext);
+ } catch (Exception e) {
+ }
+ return false;
+ }
+}
diff --git a/engine/src/main/java/com/ibm/engine/language/python/PythonDetectionEngine.java b/engine/src/main/java/com/ibm/engine/language/python/PythonDetectionEngine.java
index c56513dba..7bd9dad09 100644
--- a/engine/src/main/java/com/ibm/engine/language/python/PythonDetectionEngine.java
+++ b/engine/src/main/java/com/ibm/engine/language/python/PythonDetectionEngine.java
@@ -77,6 +77,7 @@ public Tree extractArgumentFromMethodCaller(
&& methodParameterIdentifier instanceof Name nameTree) {
// Check that we have the expected number of parameters
+ @Nonnull
Optional> parameters =
Optional.ofNullable(methodTree)
.map(FunctionDef::parameters)
@@ -110,11 +111,7 @@ public Tree extractArgumentFromMethodCaller(
Optional name =
parameters
.filter(parameterList -> finalIndex < parameterList.size())
- .map(
- parameterList ->
- Optional.ofNullable(parameterList.get(finalIndex)))
- // .filter(Objects::nonNull)
- .map(Optional::get)
+ .map(parameterList -> parameterList.get(finalIndex))
.map(org.sonar.plugins.python.api.tree.Parameter::name)
.map(Name::name);
@@ -126,8 +123,9 @@ public Tree extractArgumentFromMethodCaller(
return null;
}
+ @Nonnull
@Override
- public @Nonnull List> resolveValuesInInnerScope(
+ public List> resolveValuesInInnerScope(
@Nonnull Class clazz,
@Nonnull Tree expression,
@Nullable IValueFactory valueFactory) {
@@ -154,13 +152,14 @@ public void resolveValuesInOuterScope(
if (optionalMethodTree.isEmpty()) {
return;
}
- Tree methodTree = optionalMethodTree.get();
+ @Nonnull Tree methodTree = optionalMethodTree.get();
// If we cannot resolve the expression, it shoud be because it is an argument of the
// enclosing function. We therefore create a hook, but we need to get the argument to
// which `expressionTree` resolves to.
// To do so, we call `resolveValues` with the special parameter
// `returningEnclosingParam` set to true.
+ @Nonnull
List> resolvedValues =
PythonSemantic.resolveValues(
Object.class, expressionTree, new LinkedList<>(), null, true, this);
@@ -168,7 +167,7 @@ public void resolveValuesInOuterScope(
if (resolvedValues.size() != 1) {
return;
}
- final Tree resolvedParameter = resolvedValues.get(0).tree();
+ @Nonnull final Tree resolvedParameter = resolvedValues.get(0).tree();
createAMethodHook(methodTree, resolvedParameter, detectableParameter);
// Note that compared to the Java implementation, there is no case where we call
@@ -227,16 +226,19 @@ public void resolveMethodReturnValues(
throw new UnsupportedOperationException("Unimplemented method 'resolveMethodReturnValues'");
}
- @Override
+ @Nullable @Override
public ResolvedValue resolveEnumValue(
- Class clazz, Tree enumClassDefinition, LinkedList selections) {
+ @Nonnull Class clazz,
+ @Nonnull Tree enumClassDefinition,
+ @Nonnull LinkedList selections) {
// TODO: Enums are not a major part of Pythonm, it is left for later
// https://docs.python.org/3/library/enum.html
throw new UnsupportedOperationException("Unimplemented method 'resolveEnumValue'");
}
+ @Nonnull
@Override
- public Optional> getAssignedSymbol(Tree expression) {
+ public Optional> getAssignedSymbol(@Nonnull Tree expression) {
// When the expression is an assignment like `43` in `global_var = 43`, it will return the
// symbol of the Name `global_var`.
// In Java, `getAssignedSymbol` seem to return the symbol of the *parent* of the expression.
@@ -274,20 +276,24 @@ public Optional> getAssignedSymbol(Tree expression) {
throw new UnsupportedOperationException("Unimplemented case.");
}
+ @Nonnull
@Override
public Optional> getMethodInvocationParameterSymbol(
- Tree methodInvocationTree, Parameter parameter) {
+ @Nonnull Tree methodInvocationTree, @Nonnull Parameter parameter) {
if (methodInvocationTree instanceof CallExpression callExpression) {
- return getTraceSymbol(parameter, callExpression.arguments());
+ @Nonnull List arguments = callExpression.arguments();
+ return getTraceSymbol(parameter, arguments);
}
return Optional.empty();
}
+ @Nonnull
@Override
public Optional> getNewClassParameterSymbol(
- Tree newClass, Parameter parameter) {
+ @Nonnull Tree newClass, @Nonnull Parameter parameter) {
if (newClass instanceof CallExpression callExpression) {
- return getTraceSymbol(parameter, callExpression.arguments());
+ @Nonnull List arguments = callExpression.arguments();
+ return getTraceSymbol(parameter, arguments);
}
return Optional.empty();
}
@@ -296,45 +302,52 @@ public Optional> getNewClassParameterSymbol(
private Optional> getTraceSymbol(
@Nonnull Parameter parameter, @Nonnull List arguments) {
if (parameter.getIndex() >= arguments.size()) {
- return Optional.of(TraceSymbol.createWithStateDifferent());
+ @Nonnull
+ Optional> res = Optional.of(TraceSymbol.createWithStateDifferent());
+ return res;
}
Argument arg = arguments.get(parameter.getIndex());
if (arg instanceof RegularArgument regularArg) {
Expression expressionArg = regularArg.expression();
if (expressionArg.is(Tree.Kind.NAME)) {
Name nameArg = (Name) expressionArg;
- return Optional.of(TraceSymbol.createFrom(nameArg.symbol()));
+ @Nonnull
+ Optional> res =
+ Optional.of(TraceSymbol.createFrom(nameArg.symbol()));
+ return res;
}
}
- return Optional.of(TraceSymbol.createWithStateNoSymbol());
+ @Nonnull
+ Optional> res = Optional.of(TraceSymbol.createWithStateNoSymbol());
+ return res;
}
@Override
public boolean isInvocationOnVariable(
- Tree methodInvocation, TraceSymbol variableSymbol) {
+ @Nonnull Tree methodInvocation, @Nonnull TraceSymbol variableSymbol) {
if (methodInvocation instanceof CallExpression callExpression) {
if (!variableSymbol.is(TraceSymbol.State.SYMBOL)) {
return false;
}
Symbol variable = variableSymbol.getSymbol();
- Expression callee = callExpression.callee();
- if (variable == null || !callee.is(Tree.Kind.QUALIFIED_EXPR)) {
+ if (variable == null) {
return false;
}
- QualifiedExpression qualifiedExpression = (QualifiedExpression) callee;
- if (qualifiedExpression.qualifier() instanceof Name name) {
- Optional nameString = Optional.of(name).map(Name::symbol).map(Symbol::name);
- return nameString.isPresent() && nameString.get().equals(variable.name());
+ if (callExpression.callee() instanceof QualifiedExpression qualifiedExpression) {
+ Expression qualifier = qualifiedExpression.qualifier();
+ if (qualifier instanceof Name name) {
+ Symbol qualifierSymbol = name.symbol();
+ return variable.equals(qualifierSymbol);
+ }
}
-
- return false;
}
return false;
}
@Override
- public boolean isInitForVariable(Tree newClass, TraceSymbol variableSymbol) {
+ public boolean isInitForVariable(
+ @Nonnull Tree newClass, @Nonnull TraceSymbol variableSymbol) {
if (!variableSymbol.is(TraceSymbol.State.SYMBOL)) {
return false;
}
@@ -351,6 +364,20 @@ public boolean isInitForVariable(Tree newClass, TraceSymbol variableSymb
private void analyseExpression(
@Nonnull TraceSymbol traceSymbol, @Nonnull CallExpression expressionTree) {
+ boolean isInvocation =
+ isInvocationOnVariable(expressionTree, traceSymbol)
+ || isInitForVariable(expressionTree, traceSymbol);
+
+ // Check if the variable symbols for the method (if applicable) are connected
+ Optional assignedSymbol =
+ getAssignedSymbol(expressionTree).map(TraceSymbol::getSymbol);
+
+ if (traceSymbol.is(TraceSymbol.State.DIFFERENT)
+ || (traceSymbol.is(TraceSymbol.State.SYMBOL) && !isInvocation)
+ || (traceSymbol.is(TraceSymbol.State.NO_SYMBOL) && assignedSymbol.isPresent())) {
+ return;
+ }
+
if (detectionStore.getDetectionRule().is(MethodDetectionRule.class)) {
MethodDetection methodDetection = new MethodDetection<>(expressionTree, null);
detectionStore.onReceivingNewDetection(methodDetection);
@@ -364,22 +391,16 @@ private void analyseExpression(
}
// Extracts the arguments for the provided expression
- List arguments = expressionTree.arguments();
- boolean isInvocation =
- isInvocationOnVariable(expressionTree, traceSymbol)
- || isInitForVariable(expressionTree, traceSymbol);
- // TODO: It would be better to have a case disjunction to use either
- // isInvocationOnVariable or isInitForVariable, but it is difficult in Python
+ @Nonnull List arguments = expressionTree.arguments();
int index = 0;
for (Parameter parameter : detectionRule.parameters()) {
- if (!checkCurrentIndexState(
- index, arguments, isInvocation, traceSymbol, expressionTree)) {
+ if (arguments.size() <= index) {
index++;
continue;
}
// the expression tree of the parameter
- Tree expression = arguments.get(index); // this is an Argument tree
+ @Nonnull Tree expression = arguments.get(index); // this is an Argument tree
if (expression instanceof RegularArgument regularArgument) {
expression = regularArgument.expression();
}
@@ -392,6 +413,7 @@ private void analyseExpression(
DetectableParameter detectableParameter =
(DetectableParameter) parameter;
// try to resolve value in inner scope
+ @Nonnull
List> resolvedValues =
resolveValuesInInnerScope(
Object.class, expression, detectableParameter.getiValueFactory());
@@ -401,12 +423,14 @@ private void analyseExpression(
} else {
resolvedValues.stream()
.map(
- resolvedValue ->
- new ValueDetection<>(
- resolvedValue,
- detectableParameter,
- expressionTree,
- expressionTree))
+ resolvedValue -> {
+ @Nonnull ResolvedValue