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 new file mode 100644 index 000000000..330f637f4 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations8.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations8Query = + TDuplicateInlineFunctionDefinitionsQuery() or + TTemplateSpecializationWrongLocationQuery() or + TDuplicateTypeDefinitionsQuery() + +predicate isDeclarations8QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `duplicateInlineFunctionDefinitions` query + Declarations8Package::duplicateInlineFunctionDefinitionsQuery() and + queryId = + // `@id` for the `duplicateInlineFunctionDefinitions` query + "cpp/misra/duplicate-inline-function-definitions" 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" + 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 { + Query duplicateInlineFunctionDefinitionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `duplicateInlineFunctionDefinitions` query + TQueryCPP(TDeclarations8PackageQuery(TDuplicateInlineFunctionDefinitionsQuery())) + } + + Query templateSpecializationWrongLocationQuery() { + //autogenerate `Query` type + result = + // `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/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index f4e7cfb60..af3470014 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -40,6 +40,7 @@ import Declarations2 import Declarations3 import Declarations4 import Declarations7 +import Declarations8 import ExceptionSafety import Exceptions1 import Exceptions2 @@ -144,6 +145,7 @@ newtype TCPPQuery = TDeclarations3PackageQuery(Declarations3Query q) or TDeclarations4PackageQuery(Declarations4Query q) or TDeclarations7PackageQuery(Declarations7Query q) or + TDeclarations8PackageQuery(Declarations8Query q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or TExceptions1PackageQuery(Exceptions1Query q) or TExceptions2PackageQuery(Exceptions2Query q) or @@ -248,6 +250,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeclarations3QueryMetadata(query, queryId, ruleId, category) or isDeclarations4QueryMetadata(query, queryId, ruleId, category) or isDeclarations7QueryMetadata(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/DuplicateInlineFunctionDefinitions.ql b/cpp/misra/src/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.ql new file mode 100644 index 000000000..723027c46 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.ql @@ -0,0 +1,44 @@ +/** + * @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. + * @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.types.Compatible + +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() +} + +module FunDeclEquiv = + FunctionDeclarationTypeEquivalence; + +from FunctionDeclarationEntry d1, FunctionDeclarationEntry d2, string namespace, string name +where + not isExcluded([d1, d2], Declarations8Package::duplicateInlineFunctionDefinitionsQuery()) and + interestedInFunctions(d1, d2) and + FunDeclEquiv::equalParameterTypes(d1, d2) and + d1.getDeclaration().hasQualifiedName(namespace, name) and + d2.getDeclaration().hasQualifiedName(namespace, name) and + d1.getFile().getAbsolutePath() < d2.getFile().getAbsolutePath() +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/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..d3f9a2ce4 --- /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: 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/TemplateSpecializationWrongLocation.ql b/cpp/misra/src/rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql new file mode 100644 index 000000000..dd70eda5a --- /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: 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 + * maintainability + * 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/DuplicateInlineFunctionDefinitions.expected b/cpp/misra/test/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.expected new file mode 100644 index 000000000..a94af1d4b --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.expected @@ -0,0 +1 @@ +| 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/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/DuplicateTypeDefinitions.expected b/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected new file mode 100644 index 000000000..a1662137e --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/DuplicateTypeDefinitions.expected @@ -0,0 +1,9 @@ +| 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/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/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..4372567bf --- /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..7d3af5810 --- /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..4b614723d --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/test.cpp @@ -0,0 +1,52 @@ +#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 +inline void func_overloaded(int) {} // 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 + +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 new file mode 100644 index 000000000..2bb54a099 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-3/test2.cpp @@ -0,0 +1,47 @@ +// 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] +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 +int16_t global_noninline = 0; // COMPLIANT +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 new file mode 100644 index 000000000..a41139b01 --- /dev/null +++ b/rule_packages/cpp/Declarations8.json @@ -0,0 +1,56 @@ +{ + "MISRA-C++-2023": { + "RULE-6-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "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", + "severity": "error", + "short_name": "DuplicateInlineFunctionDefinitions", + "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.", + "kind": "problem", + "name": "Template specializations in wrong location", + "precision": "very-high", + "severity": "error", + "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": "Duplicate type definitions across files", + "precision": "very-high", + "severity": "error", + "short_name": "DuplicateTypeDefinitions", + "tags": [ + "correctness", + "maintainability", + "scope/system" + ] + } + ], + "title": "The source code used to implement an entity shall appear only once" + } + } +} \ No newline at end of file