From d79cf17f33824f00b4dbf44c00f46357868aa173 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 19 Apr 2026 14:32:41 -0700 Subject: [PATCH 1/7] initial implementation of 6-2-3 --- .../cpp/exclusions/cpp/Declarations8.qll | 44 +++++++++++++++++++ .../cpp/exclusions/cpp/RuleMetadata.qll | 3 ++ .../SourceCodeImplementedOnlyOnce.ql | 38 ++++++++++++++++ .../TemplateSpecializationWrongLocation.ql | 40 +++++++++++++++++ .../SourceCodeImplementedOnlyOnce.expected | 1 + .../SourceCodeImplementedOnlyOnce.qlref | 1 + ...mplateSpecializationWrongLocation.expected | 14 ++++++ .../TemplateSpecializationWrongLocation.qlref | 1 + cpp/misra/test/rules/RULE-6-2-3/class.h | 9 ++++ .../RULE-6-2-3/compliant_specialization.h | 17 +++++++ .../RULE-6-2-3/noncompliant_specialization.h | 19 ++++++++ cpp/misra/test/rules/RULE-6-2-3/template.h | 30 +++++++++++++ cpp/misra/test/rules/RULE-6-2-3/test.cpp | 17 +++++++ cpp/misra/test/rules/RULE-6-2-3/test2.cpp | 11 +++++ rule_packages/cpp/Declarations8.json | 37 ++++++++++++++++ 15 files changed, 282 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll create mode 100644 cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql create mode 100644 cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql create mode 100644 cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected create mode 100644 cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.qlref create mode 100644 cpp/misra/test/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.expected create mode 100644 cpp/misra/test/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.qlref create mode 100644 cpp/misra/test/rules/RULE-6-2-3/class.h create mode 100644 cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h create mode 100644 cpp/misra/test/rules/RULE-6-2-3/noncompliant_specialization.h create mode 100644 cpp/misra/test/rules/RULE-6-2-3/template.h create mode 100644 cpp/misra/test/rules/RULE-6-2-3/test.cpp create mode 100644 cpp/misra/test/rules/RULE-6-2-3/test2.cpp create mode 100644 rule_packages/cpp/Declarations8.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll new file mode 100644 index 000000000..315e25d1b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations8Query = + TSourceCodeImplementedOnlyOnceQuery() or + TTemplateSpecializationWrongLocationQuery() + +predicate isDeclarations8QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `sourceCodeImplementedOnlyOnce` query + Declarations8Package::sourceCodeImplementedOnlyOnceQuery() and + queryId = + // `@id` for the `sourceCodeImplementedOnlyOnce` query + "cpp/misra/source-code-implemented-only-once" and + ruleId = "RULE-6-2-3" and + category = "required" + or + query = + // `Query` instance for the `templateSpecializationWrongLocation` query + Declarations8Package::templateSpecializationWrongLocationQuery() and + queryId = + // `@id` for the `templateSpecializationWrongLocation` query + "cpp/misra/template-specialization-wrong-location" and + ruleId = "RULE-6-2-3" and + category = "required" +} + +module Declarations8Package { + Query sourceCodeImplementedOnlyOnceQuery() { + //autogenerate `Query` type + result = + // `Query` type for `sourceCodeImplementedOnlyOnce` query + TQueryCPP(TDeclarations8PackageQuery(TSourceCodeImplementedOnlyOnceQuery())) + } + + Query templateSpecializationWrongLocationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `templateSpecializationWrongLocation` query + TQueryCPP(TDeclarations8PackageQuery(TTemplateSpecializationWrongLocationQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 8771bbc79..cae06324c 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -39,6 +39,7 @@ import Declarations1 import Declarations2 import Declarations3 import Declarations4 +import Declarations8 import ExceptionSafety import Exceptions1 import Exceptions2 @@ -141,6 +142,7 @@ newtype TCPPQuery = TDeclarations2PackageQuery(Declarations2Query q) or TDeclarations3PackageQuery(Declarations3Query q) or TDeclarations4PackageQuery(Declarations4Query q) or + TDeclarations8PackageQuery(Declarations8Query q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or TExceptions1PackageQuery(Exceptions1Query q) or TExceptions2PackageQuery(Exceptions2Query q) or @@ -243,6 +245,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeclarations2QueryMetadata(query, queryId, ruleId, category) or isDeclarations3QueryMetadata(query, queryId, ruleId, category) or isDeclarations4QueryMetadata(query, queryId, ruleId, category) or + isDeclarations8QueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or isExceptions1QueryMetadata(query, queryId, ruleId, category) or isExceptions2QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql b/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql new file mode 100644 index 000000000..14c68c5c9 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql @@ -0,0 +1,38 @@ +/** + * @id cpp/misra/source-code-implemented-only-once + * @name RULE-6-2-3: The source code used to implement an entity shall appear only once + * @description Implementing an entity in multiple source locations violates the one-definition rule + * and leads to undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-2-3 + * correctness + * scope/system + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +predicate isInline(DeclarationEntry d) { + // There is no way to detect if a `GlobalVariable` is declared inline. + d.getDeclaration().(Function).isInline() +} + +from DeclarationEntry d1, DeclarationEntry d2, string namespace, string name +where + not isExcluded([d1, d2], Declarations8Package::sourceCodeImplementedOnlyOnceQuery()) and + d1 != d2 and + d1.isDefinition() and + d2.isDefinition() and + isInline(d1) and + isInline(d2) and + d1.getDeclaration().hasQualifiedName(namespace, name) and + d2.getDeclaration().hasQualifiedName(namespace, name) and + d1.getFile() != d2.getFile() and + d1.getFile().getAbsolutePath() < d2.getFile().getAbsolutePath() +select d1, + "Inline variable '" + d1.getName() + + "' is defined in multiple files, violating the source code uniqueness requirement." diff --git a/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql b/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql new file mode 100644 index 000000000..f3229b0a0 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql @@ -0,0 +1,40 @@ +/** + * @id cpp/misra/template-specialization-wrong-location + * @name RULE-6-2-3: RULE-6-2-3: Template specializations in wrong location + * @description Template specializations must be defined in the same file as the primary template or + * where a specialized type is defined to ensure visibility and avoid ODR violations. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-2-3 + * correctness + * scope/system + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +predicate specializedWithFileDeclaredType(ClassTemplateSpecialization spec) { + exists(Type argType | + spec.getTemplateArgument(_).(Type).getUnderlyingType() = argType and + spec.getFile() = argType.getFile() and + not argType instanceof TypeTemplateParameter + ) +} + + +from ClassTemplateSpecialization spec, Class primaryTemplate, File primaryFile +where + not isExcluded(spec, Declarations8Package::templateSpecializationWrongLocationQuery()) and + spec.getPrimaryTemplate() = primaryTemplate and + primaryFile = primaryTemplate.getFile() and + // The specialization is in a different file than the primary template + spec.getFile() != primaryFile and + // And it's not in the same file as any of its template arguments + not specializedWithFileDeclaredType(spec) +select spec, + "Template specialization '" + spec.getName() + + "' is declared in a different file than $@ and all specialized template arguments.", + primaryTemplate, primaryTemplate.getName() diff --git a/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected b/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected new file mode 100644 index 000000000..3772602be --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected @@ -0,0 +1 @@ +| test.cpp:6:13:6:26 | definition of func_redefined | Inline variable 'func_redefined' is defined in multiple files, violating the source code uniqueness requirement. | diff --git a/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.qlref b/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.qlref new file mode 100644 index 000000000..0b523f689 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.qlref @@ -0,0 +1 @@ +rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.expected b/cpp/misra/test/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.expected new file mode 100644 index 000000000..b021c6b4b --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.expected @@ -0,0 +1,14 @@ +| noncompliant_specialization.h:3:19:3:28 | Tpl1 | Template specialization 'Tpl1' is declared in a different file than $@ and all specialized template arguments. | template.h:10:29:10:32 | Tpl1 | Tpl1 | +| noncompliant_specialization.h:4:19:4:38 | Tpl1 | Template specialization 'Tpl1' is declared in a different file than $@ and all specialized template arguments. | template.h:10:29:10:32 | Tpl1 | Tpl1 | +| noncompliant_specialization.h:5:19:5:35 | Tpl1 | Template specialization 'Tpl1' is declared in a different file than $@ and all specialized template arguments. | template.h:10:29:10:32 | Tpl1 | Tpl1 | +| noncompliant_specialization.h:7:19:7:34 | Tpl2 | Template specialization 'Tpl2' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2 | Tpl2 | +| noncompliant_specialization.h:8:19:8:54 | Tpl2 | Template specialization 'Tpl2' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2 | Tpl2 | +| noncompliant_specialization.h:9:19:9:48 | Tpl2 | Template specialization 'Tpl2' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2 | Tpl2 | +| noncompliant_specialization.h:11:29:11:41 | Tpl2 | Template specialization 'Tpl2' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2 | Tpl2 | +| noncompliant_specialization.h:12:29:12:48 | Tpl2 | Template specialization 'Tpl2' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2 | Tpl2 | +| noncompliant_specialization.h:14:19:14:25 | Tpl3<1> | Template specialization 'Tpl3<1>' is declared in a different file than $@ and all specialized template arguments. | template.h:12:22:12:25 | Tpl3<> | Tpl3<> | +| noncompliant_specialization.h:15:19:15:31 | Tpl4 | Template specialization 'Tpl4' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4> | Tpl4> | +| noncompliant_specialization.h:16:19:16:41 | Tpl4 | Template specialization 'Tpl4' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4> | Tpl4> | +| noncompliant_specialization.h:17:19:17:38 | Tpl4 | Template specialization 'Tpl4' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4> | Tpl4> | +| noncompliant_specialization.h:18:24:18:43 | Tpl4 | Template specialization 'Tpl4' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4> | Tpl4> | +| noncompliant_specialization.h:19:29:19:38 | Tpl4 | Template specialization 'Tpl4' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4> | Tpl4> | diff --git a/cpp/misra/test/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.qlref b/cpp/misra/test/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.qlref new file mode 100644 index 000000000..f5c173037 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.qlref @@ -0,0 +1 @@ +rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/class.h b/cpp/misra/test/rules/RULE-6-2-3/class.h new file mode 100644 index 000000000..08033fac8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/class.h @@ -0,0 +1,9 @@ +#ifndef CLASS_H +#define CLASS_H + +namespace class_h { +class C1 {}; +class C2 {}; +} // namespace class_h + +#endif // CLASS_H \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h b/cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h new file mode 100644 index 000000000..f2a95fccc --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h @@ -0,0 +1,17 @@ +#include "class.h" +#include "template.h" + +namespace compliant_h { +class C1 {}; +} // namespace compliant_h + +template <> class Tpl1 {}; // COMPLIANT +template <> class Tpl2 {}; // COMPLIANT +template <> class Tpl2 {}; // COMPLIANT +template <> class Tpl2 {}; // COMPLIANT +template <> class Tpl2 {}; // COMPLIANT + +template class Tpl2 {}; // COMPLIANT + +template<> class Tpl4 {}; // COMPLIANT +template class Tpl4 {}; // COMPLIANT \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/noncompliant_specialization.h b/cpp/misra/test/rules/RULE-6-2-3/noncompliant_specialization.h new file mode 100644 index 000000000..f41d16813 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/noncompliant_specialization.h @@ -0,0 +1,19 @@ +#include "template.h" + +template <> class Tpl1 {}; // NON_COMPLIANT +template <> class Tpl1 {}; // NON_COMPLIANT +template <> class Tpl1 {}; // NON_COMPLIANT + +template <> class Tpl2 {}; // NON_COMPLIANT +template <> class Tpl2 {}; // NON_COMPLIANT +template <> class Tpl2 {}; // NON_COMPLIANT + +template class Tpl2 {}; // NON_COMPLIANT +template class Tpl2 {}; // NON_COMPLIANT + +template <> class Tpl3<1> {}; // NON_COMPLIANT +template <> class Tpl4 {}; // NON_COMPLIANT +template <> class Tpl4 {}; // NON_COMPLIANT +template <> class Tpl4 {}; // NON_COMPLIANT +template class Tpl4 {}; // NON_COMPLIANT +template class Tpl4 {}; // NON_COMPLIANT \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/template.h b/cpp/misra/test/rules/RULE-6-2-3/template.h new file mode 100644 index 000000000..b34c16cc9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/template.h @@ -0,0 +1,30 @@ +#ifndef TEMPLATE_H +#define TEMPLATE_H +#include "class.h" + +namespace template_h { +class C1 {}; +class C2 {}; +} // namespace template_h + +template class Tpl1 {}; +template class Tpl2 {}; +template class Tpl3 {}; +template class Tpl4 {}; + +template <> class Tpl1 {}; // COMPLIANT +template <> class Tpl1 {}; // COMPLIANT +template <> class Tpl1 {}; // COMPLIANT + +template <> class Tpl2 {}; // COMPLIANT +template <> class Tpl2 {}; // COMPLIANT +template <> class Tpl2 {}; // COMPLIANT + +template class Tpl2 {}; // COMPLIANT + +template<> class Tpl3<0> {}; // COMPLIANT +template<> class Tpl4 {}; // COMPLIANT +template<> class Tpl4 {}; // COMPLIANT +template<> class Tpl4 {}; // COMPLIANT + +#endif // TEMPLATE_H \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/test.cpp b/cpp/misra/test/rules/RULE-6-2-3/test.cpp new file mode 100644 index 000000000..1cdd0adce --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/test.cpp @@ -0,0 +1,17 @@ +#include + +inline int16_t global_redefined = 0; // NON_COMPLIANT[False negative] +inline int16_t global_unique = 0; // COMPLIANT +inline int16_t global_redeclared = 0; // COMPLIANT +inline void func_redefined() {} // NON_COMPLIANT +inline void func_unique() {} // COMPLIANT +inline void func_redeclared() {} // COMPLIANT + +// Violates our implementation of 6.2.1, but legal in our implementation +// of 6.2.3 +int16_t global_noninline = 0; // COMPLIANT +int func_noninline() { return 42; } // COMPLIANT + +#include "template.h" +#include "compliant_specialization.h" +#include "noncompliant_specialization.h" diff --git a/cpp/misra/test/rules/RULE-6-2-3/test2.cpp b/cpp/misra/test/rules/RULE-6-2-3/test2.cpp new file mode 100644 index 000000000..b85517802 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/test2.cpp @@ -0,0 +1,11 @@ +#include + +inline int16_t global_redefined = 0; // NON_COMPLIANT[False negative] +extern inline int16_t global_redeclared; // COMPLIANT +inline void func_redefined() {} // NON_COMPLIANT -- flagged in test.cpp +inline void func_redeclared(); // COMPLIANT + +// Violates our implementation of 6.2.1, but legal in our implementation +// of 6.2.3 +int16_t global_noninline = 0; // COMPLIANT +int func_noninline() { return 42; } // COMPLIANT \ No newline at end of file diff --git a/rule_packages/cpp/Declarations8.json b/rule_packages/cpp/Declarations8.json new file mode 100644 index 000000000..3bfa76c08 --- /dev/null +++ b/rule_packages/cpp/Declarations8.json @@ -0,0 +1,37 @@ +{ + "MISRA-C++-2023": { + "RULE-6-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Implementing an entity in multiple source locations violates the one-definition rule and leads to undefined behavior.", + "kind": "problem", + "name": "The source code used to implement an entity shall appear only once", + "precision": "very-high", + "severity": "error", + "short_name": "SourceCodeImplementedOnlyOnce", + "tags": [ + "correctness", + "scope/system" + ] + }, + { + "description": "Template specializations must be defined in the same file as the primary template or where a specialized type is defined to ensure visibility and avoid ODR violations.", + "kind": "problem", + "name": "RULE-6-2-3: Template specializations in wrong location", + "precision": "very-high", + "severity": "error", + "short_name": "TemplateSpecializationWrongLocation", + "tags": [ + "correctness", + "scope/system" + ] + } + ], + "title": "The source code used to implement an entity shall appear only once" + } + } +} \ No newline at end of file From fc8fb7e5e86e04fa6616ec0fe3a4220a081d52e0 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 20 Apr 2026 00:41:09 -0700 Subject: [PATCH 2/7] Finalize firs draft of Rule 6-2-3 --- ...factor-nested-anonymous-namespace-logic.md | 3 ++ .../src/codingstandards/cpp/Linkage.qll | 18 ++++---- .../cpp/exclusions/cpp/Declarations8.qll | 19 ++++++++- .../RULE-6-2-3/DuplicateTypeDefinitions.ql | 41 +++++++++++++++++++ .../SourceCodeImplementedOnlyOnce.ql | 5 ++- .../TemplateSpecializationWrongLocation.ql | 2 +- .../DuplicateTypeDefinitions.expected | 9 ++++ .../RULE-6-2-3/DuplicateTypeDefinitions.qlref | 1 + cpp/misra/test/rules/RULE-6-2-3/test.cpp | 36 +++++++++++++++- cpp/misra/test/rules/RULE-6-2-3/test2.cpp | 37 ++++++++++++++++- rule_packages/cpp/Declarations8.json | 23 ++++++++++- 11 files changed, 177 insertions(+), 17 deletions(-) create mode 100644 change_notes/2026-04-19-refactor-nested-anonymous-namespace-logic.md create mode 100644 cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql create mode 100644 cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected create mode 100644 cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.qlref diff --git a/change_notes/2026-04-19-refactor-nested-anonymous-namespace-logic.md b/change_notes/2026-04-19-refactor-nested-anonymous-namespace-logic.md new file mode 100644 index 000000000..bc3438d55 --- /dev/null +++ b/change_notes/2026-04-19-refactor-nested-anonymous-namespace-logic.md @@ -0,0 +1,3 @@ + - All queries using `Linkage.qll`: + - The logic for determining whether a namespace is within an anonymous namespace, directly or indirectly, has been refactored. + - No visible change in behavior or performance is expected. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Linkage.qll b/cpp/common/src/codingstandards/cpp/Linkage.qll index 6ecab3f6b..e0d1b8dc6 100644 --- a/cpp/common/src/codingstandards/cpp/Linkage.qll +++ b/cpp/common/src/codingstandards/cpp/Linkage.qll @@ -17,7 +17,7 @@ private predicate isSpecificationVariable(Variable v) { /** Holds if `elem` has internal linkage. */ predicate hasInternalLinkage(Element elem) { // An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage - directlyOrIndirectlyUnnnamedNamespace(elem) + elem instanceof WithinAnonymousNamespace or exists(Declaration decl | decl = elem | // A name having namespace scope has internal linkage if it is the name of @@ -46,7 +46,7 @@ predicate hasInternalLinkage(Element elem) { ) ) or - directlyOrIndirectlyUnnnamedNamespace(decl.getNamespace()) and + decl.getNamespace() instanceof WithinAnonymousNamespace and inheritsLinkageOfNamespace(decl.getNamespace(), decl) or exists(Class klass | @@ -59,12 +59,12 @@ predicate hasInternalLinkage(Element elem) { /** Holds if `elem` has external linkage. */ predicate hasExternalLinkage(Element elem) { elem instanceof Namespace and - not directlyOrIndirectlyUnnnamedNamespace(elem) + not elem instanceof WithinAnonymousNamespace or not hasInternalLinkage(elem) and exists(Declaration decl | decl = elem | // A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of - not directlyOrIndirectlyUnnnamedNamespace(decl.getNamespace()) and + not decl.getNamespace() instanceof WithinAnonymousNamespace and inheritsLinkageOfNamespace(decl.getNamespace(), decl) or exists(Class klass | @@ -74,11 +74,11 @@ predicate hasExternalLinkage(Element elem) { ) } -private predicate directlyOrIndirectlyUnnnamedNamespace(Namespace ns) { - exists(Namespace anonymous | - anonymous.isAnonymous() and - ns = anonymous.getAChildNamespace*() - ) +/** + * A `Namespace` that is anonymous or indirectly contained within an unnamed namespace. + */ +class WithinAnonymousNamespace extends Namespace { + WithinAnonymousNamespace() { getParentNamespace*().isAnonymous() } } private predicate hasLinkageOfTypedef(TypedefType typedef, Element decl) { diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll index 315e25d1b..cdf365361 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll @@ -5,7 +5,8 @@ import codingstandards.cpp.exclusions.RuleMetadata newtype Declarations8Query = TSourceCodeImplementedOnlyOnceQuery() or - TTemplateSpecializationWrongLocationQuery() + TTemplateSpecializationWrongLocationQuery() or + TDuplicateTypeDefinitionsQuery() predicate isDeclarations8QueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -25,6 +26,15 @@ predicate isDeclarations8QueryMetadata(Query query, string queryId, string ruleI "cpp/misra/template-specialization-wrong-location" and ruleId = "RULE-6-2-3" and category = "required" + or + query = + // `Query` instance for the `duplicateTypeDefinitions` query + Declarations8Package::duplicateTypeDefinitionsQuery() and + queryId = + // `@id` for the `duplicateTypeDefinitions` query + "cpp/misra/duplicate-type-definitions" and + ruleId = "RULE-6-2-3" and + category = "required" } module Declarations8Package { @@ -41,4 +51,11 @@ module Declarations8Package { // `Query` type for `templateSpecializationWrongLocation` query TQueryCPP(TDeclarations8PackageQuery(TTemplateSpecializationWrongLocationQuery())) } + + Query duplicateTypeDefinitionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `duplicateTypeDefinitions` query + TQueryCPP(TDeclarations8PackageQuery(TDuplicateTypeDefinitionsQuery())) + } } diff --git a/cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql b/cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql new file mode 100644 index 000000000..a28ec1abc --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql @@ -0,0 +1,41 @@ +/** + * @id cpp/misra/duplicate-type-definitions + * @name RULE-6-2-3: RULE-6-2-3: Duplicate type definitions across files + * @description Defining a type with the same fully qualified name in multiple files increases the + * risk of ODR violations and undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-2-3 + * correctness + * maintainability + * scope/system + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.Linkage + +class UserTypeDefinition extends TypeDeclarationEntry { + UserTypeDefinition() { + (isDefinition() or getDeclaration() instanceof TypedefType) and + not getDeclaration().(Class).isAnonymous() and + not getDeclaration().(Union).isAnonymous() and + not getDeclaration().(Enum).isAnonymous() and + not getDeclaration() instanceof ClassTemplateSpecialization and + not getDeclaration().getNamespace() instanceof WithinAnonymousNamespace + } + + UserType getUserType() { result = getDeclaration() } +} + +from UserTypeDefinition t1, UserTypeDefinition t2 +where + not isExcluded(t1, Declarations8Package::duplicateTypeDefinitionsQuery()) and + t1.getUserType().getQualifiedName() = t2.getUserType().getQualifiedName() and + t1.getFile() != t2.getFile() and + t1.getFile().getAbsolutePath() < t2.getFile().getAbsolutePath() // Report only once per pair +select t1, "Type '" + t1.getUserType().getQualifiedName() + "' is defined in files $@ and $@.", t1, + t1.getFile().getBaseName(), t2, t2.getFile().getBaseName() diff --git a/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql b/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql index 14c68c5c9..5e484b5a6 100644 --- a/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql +++ b/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql @@ -1,13 +1,14 @@ /** * @id cpp/misra/source-code-implemented-only-once * @name RULE-6-2-3: The source code used to implement an entity shall appear only once - * @description Implementing an entity in multiple source locations violates the one-definition rule - * and leads to undefined behavior. + * @description Implementing an entity in multiple source locations increases the risk of ODR + * violations and undefined behavior. * @kind problem * @precision very-high * @problem.severity error * @tags external/misra/id/rule-6-2-3 * correctness + * maintainability * scope/system * external/misra/enforcement/decidable * external/misra/obligation/required diff --git a/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql b/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql index f3229b0a0..d82214ffc 100644 --- a/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql +++ b/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-6-2-3 * correctness + * maintainability * scope/system * external/misra/enforcement/decidable * external/misra/obligation/required @@ -24,7 +25,6 @@ predicate specializedWithFileDeclaredType(ClassTemplateSpecialization spec) { ) } - from ClassTemplateSpecialization spec, Class primaryTemplate, File primaryFile where not isExcluded(spec, Declarations8Package::templateSpecializationWrongLocationQuery()) and diff --git a/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected b/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected new file mode 100644 index 000000000..8c22970e5 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected @@ -0,0 +1,9 @@ +| test.cpp:15:8:15:22 | definition of StructRedefined | Type 'StructRedefined' is defined in files $@ and $@. | test.cpp:15:8:15:22 | definition of StructRedefined | test.cpp | test2.cpp:16:8:16:22 | definition of StructRedefined | test2.cpp | +| test.cpp:22:29:22:40 | definition of TplRedefined | Type 'TplRedefined' is defined in files $@ and $@. | test.cpp:22:29:22:40 | definition of TplRedefined | test.cpp | test2.cpp:22:29:22:40 | definition of TplRedefined | test2.cpp | +| test.cpp:26:6:26:18 | definition of DuplicateEnum | Type 'DuplicateEnum' is defined in files $@ and $@. | test.cpp:26:6:26:18 | definition of DuplicateEnum | test.cpp | test2.cpp:25:6:25:18 | definition of DuplicateEnum | test2.cpp | +| test.cpp:27:12:27:29 | definition of DuplicateEnumClass | Type 'DuplicateEnumClass' is defined in files $@ and $@. | test.cpp:27:12:27:29 | definition of DuplicateEnumClass | test.cpp | test2.cpp:26:12:26:29 | definition of DuplicateEnumClass | test2.cpp | +| test.cpp:29:17:29:32 | declaration of DuplicateTypedef | Type 'DuplicateTypedef' is defined in files $@ and $@. | test.cpp:29:17:29:32 | declaration of DuplicateTypedef | test.cpp | test2.cpp:28:17:28:32 | declaration of DuplicateTypedef | test2.cpp | +| test.cpp:30:7:30:20 | declaration of DuplicateUsing | Type 'DuplicateUsing' is defined in files $@ and $@. | test.cpp:30:7:30:20 | declaration of DuplicateUsing | test.cpp | test2.cpp:29:7:29:20 | declaration of DuplicateUsing | test2.cpp | +| test.cpp:31:7:31:20 | definition of DuplicateUnion | Type 'DuplicateUnion' is defined in files $@ and $@. | test.cpp:31:7:31:20 | definition of DuplicateUnion | test.cpp | test2.cpp:30:7:30:20 | definition of DuplicateUnion | test2.cpp | +| test.cpp:36:7:36:11 | definition of Outer | Type 'ns1::Outer' is defined in files $@ and $@. | test.cpp:36:7:36:11 | definition of Outer | test.cpp | test2.cpp:35:7:35:11 | definition of Outer | test2.cpp | +| test.cpp:37:9:37:13 | definition of Inner | Type 'ns1::Outer::Inner' is defined in files $@ and $@. | test.cpp:37:9:37:13 | definition of Inner | test.cpp | test2.cpp:36:9:36:13 | definition of Inner | test2.cpp | diff --git a/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.qlref b/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.qlref new file mode 100644 index 000000000..a8c1386af --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.qlref @@ -0,0 +1 @@ +rules/RULE-6-2-3/DuplicateTypeDefinitions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/test.cpp b/cpp/misra/test/rules/RULE-6-2-3/test.cpp index 1cdd0adce..fa7dbb1d4 100644 --- a/cpp/misra/test/rules/RULE-6-2-3/test.cpp +++ b/cpp/misra/test/rules/RULE-6-2-3/test.cpp @@ -12,6 +12,40 @@ inline void func_redeclared() {} // COMPLIANT int16_t global_noninline = 0; // COMPLIANT int func_noninline() { return 42; } // COMPLIANT -#include "template.h" +struct StructRedefined {}; // NON_COMPLIANT +struct StructUnique {}; // COMPLIANT +struct StructRedeclared {}; // COMPLIANT +struct IncompleteStruct; // COMPLIANT +struct { +} anonymousStruct1; // COMPLIANT + +template class TplRedefined {}; // NON_COMPLIANT +template class TplUnique {}; // COMPLIANT +template class TplRedeclared {}; // COMPLIANT + +enum DuplicateEnum {}; // NON_COMPLIANT +enum class DuplicateEnumClass {}; // NON_COMPLIANT +enum {} anonymousEnum1; // COMPLIANT +typedef int16_t DuplicateTypedef; // NON_COMPLIANT +using DuplicateUsing = int16_t; // NON_COMPLIANT +union DuplicateUnion {}; // NON_COMPLIANT +union { +} anonymousUnion1; // COMPLIANT + +namespace ns1 { +class Outer { // NON_COMPLIANT + class Inner {}; // NON_COMPLIANT +}; + +namespace { +class AnonymousClass {}; // COMPLIANT +} // namespace +} // namespace ns1 + +void f() { + auto x = []() { return 42; }; // COMPLIANT +} + #include "compliant_specialization.h" #include "noncompliant_specialization.h" +#include "template.h" diff --git a/cpp/misra/test/rules/RULE-6-2-3/test2.cpp b/cpp/misra/test/rules/RULE-6-2-3/test2.cpp index b85517802..1078dddff 100644 --- a/cpp/misra/test/rules/RULE-6-2-3/test2.cpp +++ b/cpp/misra/test/rules/RULE-6-2-3/test2.cpp @@ -1,3 +1,6 @@ +// Note: the COMPLIANT/NON_COMPLIANT comments are here for documentary purposes; +// we do not expect alerts in this file. These should be flagged in `test.cpp`. + #include inline int16_t global_redefined = 0; // NON_COMPLIANT[False negative] @@ -8,4 +11,36 @@ inline void func_redeclared(); // COMPLIANT // Violates our implementation of 6.2.1, but legal in our implementation // of 6.2.3 int16_t global_noninline = 0; // COMPLIANT -int func_noninline() { return 42; } // COMPLIANT \ No newline at end of file +int func_noninline() { return 42; } // COMPLIANT + +struct StructRedefined {}; // NON_COMPLIANT +struct StructRedeclared; // COMPLIANT +struct IncompleteStruct; // COMPLIANT +struct { +} anonymousStruct2; // COMPLIANT + +template class TplRedefined {}; // NON_COMPLIANT +template class TplRedeclared; // COMPLIANT + +enum DuplicateEnum {}; // NON_COMPLIANT +enum class DuplicateEnumClass {}; // NON_COMPLIANT +enum {} anonymousEnum1; // COMPLIANT +typedef int16_t DuplicateTypedef; // NON_COMPLIANT +using DuplicateUsing = int16_t; // NON_COMPLIANT +union DuplicateUnion {}; // NON_COMPLIANT +union { +} anonymousUnion2; // COMPLIANT + +namespace ns1 { +class Outer { // NON_COMPLIANT + class Inner {}; // NON_COMPLIANT +}; + +namespace { +class AnonymousClass {}; // COMPLIANT +} // namespace +} // namespace ns1 + +void f2() { + auto x = []() { return 42; }; // COMPLIANT +} \ No newline at end of file diff --git a/rule_packages/cpp/Declarations8.json b/rule_packages/cpp/Declarations8.json index 3bfa76c08..fccd5ccf4 100644 --- a/rule_packages/cpp/Declarations8.json +++ b/rule_packages/cpp/Declarations8.json @@ -7,7 +7,7 @@ }, "queries": [ { - "description": "Implementing an entity in multiple source locations violates the one-definition rule and leads to undefined behavior.", + "description": "Implementing an entity in multiple source locations increases the risk of ODR violations and undefined behavior.", "kind": "problem", "name": "The source code used to implement an entity shall appear only once", "precision": "very-high", @@ -15,8 +15,13 @@ "short_name": "SourceCodeImplementedOnlyOnce", "tags": [ "correctness", + "maintainability", "scope/system" - ] + ], + "implementation_scope": { + "description": "This query does not detect duplicated definitions of inline variables.", + "items": [] + } }, { "description": "Template specializations must be defined in the same file as the primary template or where a specialized type is defined to ensure visibility and avoid ODR violations.", @@ -27,6 +32,20 @@ "short_name": "TemplateSpecializationWrongLocation", "tags": [ "correctness", + "maintainability", + "scope/system" + ] + }, + { + "description": "Defining a type with the same fully qualified name in multiple files increases the risk of ODR violations and undefined behavior.", + "kind": "problem", + "name": "RULE-6-2-3: Duplicate type definitions across files", + "precision": "very-high", + "severity": "error", + "short_name": "DuplicateTypeDefinitions", + "tags": [ + "correctness", + "maintainability", "scope/system" ] } From ee92f8990dc4dc5581303dfd0478c8046efb15a0 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 20 Apr 2026 10:39:05 -0700 Subject: [PATCH 3/7] Commit rules.csv changes --- rules.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.csv b/rules.csv index 7abe0599a..09d4de3db 100644 --- a/rules.csv +++ b/rules.csv @@ -855,7 +855,7 @@ cpp,MISRA-C++-2023,RULE-6-0-3,Yes,Advisory,Decidable,Single Translation Unit,"Th cpp,MISRA-C++-2023,RULE-6-0-4,Yes,Required,Decidable,Single Translation Unit,The identifier main shall not be used for a function other than the global function main,M7-3-2,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-2-1,Yes,Required,Decidable,System,The one-definition rule shall not be violated,M3-2-2,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-2-2,Yes,Required,Decidable,System,All declarations of a variable or function shall have the same type,"M3-9-1,DCL40-C",Declarations2,Easy, -cpp,MISRA-C++-2023,RULE-6-2-3,Yes,Required,Decidable,System,The source code used to implement an entity shall appear only once,,Declarations7,Medium, +cpp,MISRA-C++-2023,RULE-6-2-3,Yes,Required,Decidable,System,The source code used to implement an entity shall appear only once,,Declarations8,Medium, cpp,MISRA-C++-2023,RULE-6-2-4,Yes,Required,Decidable,Single Translation Unit,A header file shall not contain definitions of functions or objects that are non-inline and have external linkage,A3-1-1,Linkage2,Import, cpp,MISRA-C++-2023,RULE-6-4-1,Yes,Required,Decidable,Single Translation Unit,A variable declared in an inner scope shall not hide a variable declared in an outer scope,A2-10-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-6-4-2,Yes,Required,Decidable,Single Translation Unit,Derived classes shall not conceal functions that are inherited from their bases,A7-3-1,ImportMisra23,Import, From ac06fe8e971a22767a5b0fff0bf8f27a3badf849 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 20 Apr 2026 10:39:36 -0700 Subject: [PATCH 4/7] Remove duplicate name/rule text --- cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql | 2 +- .../rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql | 2 +- rule_packages/cpp/Declarations8.json | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql b/cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql index a28ec1abc..d3f9a2ce4 100644 --- a/cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql +++ b/cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql @@ -1,6 +1,6 @@ /** * @id cpp/misra/duplicate-type-definitions - * @name RULE-6-2-3: RULE-6-2-3: Duplicate type definitions across files + * @name RULE-6-2-3: Duplicate type definitions across files * @description Defining a type with the same fully qualified name in multiple files increases the * risk of ODR violations and undefined behavior. * @kind problem diff --git a/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql b/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql index d82214ffc..dd70eda5a 100644 --- a/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql +++ b/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql @@ -1,6 +1,6 @@ /** * @id cpp/misra/template-specialization-wrong-location - * @name RULE-6-2-3: RULE-6-2-3: Template specializations in wrong location + * @name RULE-6-2-3: Template specializations in wrong location * @description Template specializations must be defined in the same file as the primary template or * where a specialized type is defined to ensure visibility and avoid ODR violations. * @kind problem diff --git a/rule_packages/cpp/Declarations8.json b/rule_packages/cpp/Declarations8.json index fccd5ccf4..d85187921 100644 --- a/rule_packages/cpp/Declarations8.json +++ b/rule_packages/cpp/Declarations8.json @@ -26,7 +26,7 @@ { "description": "Template specializations must be defined in the same file as the primary template or where a specialized type is defined to ensure visibility and avoid ODR violations.", "kind": "problem", - "name": "RULE-6-2-3: Template specializations in wrong location", + "name": "Template specializations in wrong location", "precision": "very-high", "severity": "error", "short_name": "TemplateSpecializationWrongLocation", @@ -39,7 +39,7 @@ { "description": "Defining a type with the same fully qualified name in multiple files increases the risk of ODR violations and undefined behavior.", "kind": "problem", - "name": "RULE-6-2-3: Duplicate type definitions across files", + "name": "Duplicate type definitions across files", "precision": "very-high", "severity": "error", "short_name": "DuplicateTypeDefinitions", From bfdc09a1f2dc40b21bd949e9de795ed9b137b770 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 20 Apr 2026 14:11:27 -0700 Subject: [PATCH 5/7] Handle overloads --- .../SourceCodeImplementedOnlyOnce.ql | 31 +++++++++++-------- .../DuplicateTypeDefinitions.expected | 18 +++++------ cpp/misra/test/rules/RULE-6-2-3/test.cpp | 1 + cpp/misra/test/rules/RULE-6-2-3/test2.cpp | 1 + 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql b/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql index 5e484b5a6..2d3096c17 100644 --- a/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql +++ b/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql @@ -16,24 +16,29 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.types.Compatible -predicate isInline(DeclarationEntry d) { - // There is no way to detect if a `GlobalVariable` is declared inline. - d.getDeclaration().(Function).isInline() +predicate isInline(FunctionDeclarationEntry d) { d.getDeclaration().isInline() } + +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + f1.isDefinition() and + f2.isDefinition() and + f1.getDeclaration().getQualifiedName() = f2.getDeclaration().getQualifiedName() and + isInline(f1) and + isInline(f2) and + not f1.getFile() = f2.getFile() } -from DeclarationEntry d1, DeclarationEntry d2, string namespace, string name +module FunDeclEquiv = + FunctionDeclarationTypeEquivalence; + +from FunctionDeclarationEntry d1, FunctionDeclarationEntry d2, string namespace, string name where not isExcluded([d1, d2], Declarations8Package::sourceCodeImplementedOnlyOnceQuery()) and - d1 != d2 and - d1.isDefinition() and - d2.isDefinition() and - isInline(d1) and - isInline(d2) and + interestedInFunctions(d1, d2) and + FunDeclEquiv::equalParameterTypes(d1, d2) and d1.getDeclaration().hasQualifiedName(namespace, name) and d2.getDeclaration().hasQualifiedName(namespace, name) and - d1.getFile() != d2.getFile() and d1.getFile().getAbsolutePath() < d2.getFile().getAbsolutePath() -select d1, - "Inline variable '" + d1.getName() + - "' is defined in multiple files, violating the source code uniqueness requirement." +select d1, "Inline function '" + d1.getName() + "' is implemented in multiple files: $@ and $@.", + d1, d1.getFile().getBaseName(), d2, d2.getFile().getBaseName() diff --git a/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected b/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected index 8c22970e5..a1662137e 100644 --- a/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected +++ b/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected @@ -1,9 +1,9 @@ -| test.cpp:15:8:15:22 | definition of StructRedefined | Type 'StructRedefined' is defined in files $@ and $@. | test.cpp:15:8:15:22 | definition of StructRedefined | test.cpp | test2.cpp:16:8:16:22 | definition of StructRedefined | test2.cpp | -| test.cpp:22:29:22:40 | definition of TplRedefined | Type 'TplRedefined' is defined in files $@ and $@. | test.cpp:22:29:22:40 | definition of TplRedefined | test.cpp | test2.cpp:22:29:22:40 | definition of TplRedefined | test2.cpp | -| test.cpp:26:6:26:18 | definition of DuplicateEnum | Type 'DuplicateEnum' is defined in files $@ and $@. | test.cpp:26:6:26:18 | definition of DuplicateEnum | test.cpp | test2.cpp:25:6:25:18 | definition of DuplicateEnum | test2.cpp | -| test.cpp:27:12:27:29 | definition of DuplicateEnumClass | Type 'DuplicateEnumClass' is defined in files $@ and $@. | test.cpp:27:12:27:29 | definition of DuplicateEnumClass | test.cpp | test2.cpp:26:12:26:29 | definition of DuplicateEnumClass | test2.cpp | -| test.cpp:29:17:29:32 | declaration of DuplicateTypedef | Type 'DuplicateTypedef' is defined in files $@ and $@. | test.cpp:29:17:29:32 | declaration of DuplicateTypedef | test.cpp | test2.cpp:28:17:28:32 | declaration of DuplicateTypedef | test2.cpp | -| test.cpp:30:7:30:20 | declaration of DuplicateUsing | Type 'DuplicateUsing' is defined in files $@ and $@. | test.cpp:30:7:30:20 | declaration of DuplicateUsing | test.cpp | test2.cpp:29:7:29:20 | declaration of DuplicateUsing | test2.cpp | -| test.cpp:31:7:31:20 | definition of DuplicateUnion | Type 'DuplicateUnion' is defined in files $@ and $@. | test.cpp:31:7:31:20 | definition of DuplicateUnion | test.cpp | test2.cpp:30:7:30:20 | definition of DuplicateUnion | test2.cpp | -| test.cpp:36:7:36:11 | definition of Outer | Type 'ns1::Outer' is defined in files $@ and $@. | test.cpp:36:7:36:11 | definition of Outer | test.cpp | test2.cpp:35:7:35:11 | definition of Outer | test2.cpp | -| test.cpp:37:9:37:13 | definition of Inner | Type 'ns1::Outer::Inner' is defined in files $@ and $@. | test.cpp:37:9:37:13 | definition of Inner | test.cpp | test2.cpp:36:9:36:13 | definition of Inner | test2.cpp | +| test.cpp:16:8:16:22 | definition of StructRedefined | Type 'StructRedefined' is defined in files $@ and $@. | test.cpp:16:8:16:22 | definition of StructRedefined | test.cpp | test2.cpp:17:8:17:22 | definition of StructRedefined | test2.cpp | +| test.cpp:23:29:23:40 | definition of TplRedefined | Type 'TplRedefined' is defined in files $@ and $@. | test.cpp:23:29:23:40 | definition of TplRedefined | test.cpp | test2.cpp:23:29:23:40 | definition of TplRedefined | test2.cpp | +| test.cpp:27:6:27:18 | definition of DuplicateEnum | Type 'DuplicateEnum' is defined in files $@ and $@. | test.cpp:27:6:27:18 | definition of DuplicateEnum | test.cpp | test2.cpp:26:6:26:18 | definition of DuplicateEnum | test2.cpp | +| test.cpp:28:12:28:29 | definition of DuplicateEnumClass | Type 'DuplicateEnumClass' is defined in files $@ and $@. | test.cpp:28:12:28:29 | definition of DuplicateEnumClass | test.cpp | test2.cpp:27:12:27:29 | definition of DuplicateEnumClass | test2.cpp | +| test.cpp:30:17:30:32 | declaration of DuplicateTypedef | Type 'DuplicateTypedef' is defined in files $@ and $@. | test.cpp:30:17:30:32 | declaration of DuplicateTypedef | test.cpp | test2.cpp:29:17:29:32 | declaration of DuplicateTypedef | test2.cpp | +| test.cpp:31:7:31:20 | declaration of DuplicateUsing | Type 'DuplicateUsing' is defined in files $@ and $@. | test.cpp:31:7:31:20 | declaration of DuplicateUsing | test.cpp | test2.cpp:30:7:30:20 | declaration of DuplicateUsing | test2.cpp | +| test.cpp:32:7:32:20 | definition of DuplicateUnion | Type 'DuplicateUnion' is defined in files $@ and $@. | test.cpp:32:7:32:20 | definition of DuplicateUnion | test.cpp | test2.cpp:31:7:31:20 | definition of DuplicateUnion | test2.cpp | +| test.cpp:37:7:37:11 | definition of Outer | Type 'ns1::Outer' is defined in files $@ and $@. | test.cpp:37:7:37:11 | definition of Outer | test.cpp | test2.cpp:36:7:36:11 | definition of Outer | test2.cpp | +| test.cpp:38:9:38:13 | definition of Inner | Type 'ns1::Outer::Inner' is defined in files $@ and $@. | test.cpp:38:9:38:13 | definition of Inner | test.cpp | test2.cpp:37:9:37:13 | definition of Inner | test2.cpp | diff --git a/cpp/misra/test/rules/RULE-6-2-3/test.cpp b/cpp/misra/test/rules/RULE-6-2-3/test.cpp index fa7dbb1d4..4b614723d 100644 --- a/cpp/misra/test/rules/RULE-6-2-3/test.cpp +++ b/cpp/misra/test/rules/RULE-6-2-3/test.cpp @@ -6,6 +6,7 @@ inline int16_t global_redeclared = 0; // COMPLIANT inline void func_redefined() {} // NON_COMPLIANT inline void func_unique() {} // COMPLIANT inline void func_redeclared() {} // COMPLIANT +inline void func_overloaded(int) {} // COMPLIANT // Violates our implementation of 6.2.1, but legal in our implementation // of 6.2.3 diff --git a/cpp/misra/test/rules/RULE-6-2-3/test2.cpp b/cpp/misra/test/rules/RULE-6-2-3/test2.cpp index 1078dddff..2bb54a099 100644 --- a/cpp/misra/test/rules/RULE-6-2-3/test2.cpp +++ b/cpp/misra/test/rules/RULE-6-2-3/test2.cpp @@ -7,6 +7,7 @@ inline int16_t global_redefined = 0; // NON_COMPLIANT[False negative] extern inline int16_t global_redeclared; // COMPLIANT inline void func_redefined() {} // NON_COMPLIANT -- flagged in test.cpp inline void func_redeclared(); // COMPLIANT +inline void func_overloaded(double) {} // COMPLIANT // Violates our implementation of 6.2.1, but legal in our implementation // of 6.2.3 From 5a72bef6016a34aebb1c186fca3469cc901aaea9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 20 Apr 2026 14:17:03 -0700 Subject: [PATCH 6/7] Fix test formatting --- .../RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected | 2 +- .../test/rules/RULE-6-2-3/compliant_specialization.h | 4 ++-- cpp/misra/test/rules/RULE-6-2-3/template.h | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected b/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected index 3772602be..a94af1d4b 100644 --- a/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected +++ b/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected @@ -1 +1 @@ -| test.cpp:6:13:6:26 | definition of func_redefined | Inline variable 'func_redefined' is defined in multiple files, violating the source code uniqueness requirement. | +| test.cpp:6:13:6:26 | definition of func_redefined | Inline function 'func_redefined' is implemented in multiple files: $@ and $@. | test.cpp:6:13:6:26 | definition of func_redefined | test.cpp | test2.cpp:8:13:8:26 | definition of func_redefined | test2.cpp | diff --git a/cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h b/cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h index f2a95fccc..4372567bf 100644 --- a/cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h +++ b/cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h @@ -13,5 +13,5 @@ template <> class Tpl2 {}; // COMPLIANT template class Tpl2 {}; // COMPLIANT -template<> class Tpl4 {}; // COMPLIANT -template class Tpl4 {}; // COMPLIANT \ No newline at end of file +template <> class Tpl4 {}; // COMPLIANT +template class Tpl4 {}; // COMPLIANT \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/template.h b/cpp/misra/test/rules/RULE-6-2-3/template.h index b34c16cc9..7d3af5810 100644 --- a/cpp/misra/test/rules/RULE-6-2-3/template.h +++ b/cpp/misra/test/rules/RULE-6-2-3/template.h @@ -22,9 +22,9 @@ template <> class Tpl2 {}; // COMPLIANT template class Tpl2 {}; // COMPLIANT -template<> class Tpl3<0> {}; // COMPLIANT -template<> class Tpl4 {}; // COMPLIANT -template<> class Tpl4 {}; // COMPLIANT -template<> class Tpl4 {}; // COMPLIANT +template <> class Tpl3<0> {}; // COMPLIANT +template <> class Tpl4 {}; // COMPLIANT +template <> class Tpl4 {}; // COMPLIANT +template <> class Tpl4 {}; // COMPLIANT #endif // TEMPLATE_H \ No newline at end of file From 8566bb2c473069d5bb04d7de601926a850cba479 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 20 Apr 2026 14:19:29 -0700 Subject: [PATCH 7/7] Rename SourceCodeImplementedOnlyOnce to handle just inline funcs. --- .../cpp/exclusions/cpp/Declarations8.qll | 16 ++++++++-------- ....ql => DuplicateInlineFunctionDefinitions.ql} | 4 ++-- ... DuplicateInlineFunctionDefinitions.expected} | 0 .../DuplicateInlineFunctionDefinitions.qlref | 1 + .../SourceCodeImplementedOnlyOnce.qlref | 1 - rule_packages/cpp/Declarations8.json | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) rename cpp/misra/src/rules/RULE-6-2-3/{SourceCodeImplementedOnlyOnce.ql => DuplicateInlineFunctionDefinitions.ql} (91%) rename cpp/misra/test/rules/RULE-6-2-3/{SourceCodeImplementedOnlyOnce.expected => DuplicateInlineFunctionDefinitions.expected} (100%) create mode 100644 cpp/misra/test/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.qlref delete mode 100644 cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.qlref diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll index cdf365361..330f637f4 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll @@ -4,17 +4,17 @@ import RuleMetadata import codingstandards.cpp.exclusions.RuleMetadata newtype Declarations8Query = - TSourceCodeImplementedOnlyOnceQuery() or + TDuplicateInlineFunctionDefinitionsQuery() or TTemplateSpecializationWrongLocationQuery() or TDuplicateTypeDefinitionsQuery() predicate isDeclarations8QueryMetadata(Query query, string queryId, string ruleId, string category) { query = - // `Query` instance for the `sourceCodeImplementedOnlyOnce` query - Declarations8Package::sourceCodeImplementedOnlyOnceQuery() and + // `Query` instance for the `duplicateInlineFunctionDefinitions` query + Declarations8Package::duplicateInlineFunctionDefinitionsQuery() and queryId = - // `@id` for the `sourceCodeImplementedOnlyOnce` query - "cpp/misra/source-code-implemented-only-once" and + // `@id` for the `duplicateInlineFunctionDefinitions` query + "cpp/misra/duplicate-inline-function-definitions" and ruleId = "RULE-6-2-3" and category = "required" or @@ -38,11 +38,11 @@ predicate isDeclarations8QueryMetadata(Query query, string queryId, string ruleI } module Declarations8Package { - Query sourceCodeImplementedOnlyOnceQuery() { + Query duplicateInlineFunctionDefinitionsQuery() { //autogenerate `Query` type result = - // `Query` type for `sourceCodeImplementedOnlyOnce` query - TQueryCPP(TDeclarations8PackageQuery(TSourceCodeImplementedOnlyOnceQuery())) + // `Query` type for `duplicateInlineFunctionDefinitions` query + TQueryCPP(TDeclarations8PackageQuery(TDuplicateInlineFunctionDefinitionsQuery())) } Query templateSpecializationWrongLocationQuery() { diff --git a/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql b/cpp/misra/src/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.ql similarity index 91% rename from cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql rename to cpp/misra/src/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.ql index 2d3096c17..723027c46 100644 --- a/cpp/misra/src/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql +++ b/cpp/misra/src/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.ql @@ -1,5 +1,5 @@ /** - * @id cpp/misra/source-code-implemented-only-once + * @id cpp/misra/duplicate-inline-function-definitions * @name RULE-6-2-3: The source code used to implement an entity shall appear only once * @description Implementing an entity in multiple source locations increases the risk of ODR * violations and undefined behavior. @@ -34,7 +34,7 @@ module FunDeclEquiv = from FunctionDeclarationEntry d1, FunctionDeclarationEntry d2, string namespace, string name where - not isExcluded([d1, d2], Declarations8Package::sourceCodeImplementedOnlyOnceQuery()) and + not isExcluded([d1, d2], Declarations8Package::duplicateInlineFunctionDefinitionsQuery()) and interestedInFunctions(d1, d2) and FunDeclEquiv::equalParameterTypes(d1, d2) and d1.getDeclaration().hasQualifiedName(namespace, name) and diff --git a/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected b/cpp/misra/test/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.expected similarity index 100% rename from cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.expected rename to cpp/misra/test/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.expected diff --git a/cpp/misra/test/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.qlref b/cpp/misra/test/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.qlref new file mode 100644 index 000000000..55a706674 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.qlref @@ -0,0 +1 @@ +rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.qlref b/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.qlref deleted file mode 100644 index 0b523f689..000000000 --- a/cpp/misra/test/rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-6-2-3/SourceCodeImplementedOnlyOnce.ql \ No newline at end of file diff --git a/rule_packages/cpp/Declarations8.json b/rule_packages/cpp/Declarations8.json index d85187921..a41139b01 100644 --- a/rule_packages/cpp/Declarations8.json +++ b/rule_packages/cpp/Declarations8.json @@ -12,7 +12,7 @@ "name": "The source code used to implement an entity shall appear only once", "precision": "very-high", "severity": "error", - "short_name": "SourceCodeImplementedOnlyOnce", + "short_name": "DuplicateInlineFunctionDefinitions", "tags": [ "correctness", "maintainability",