Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@
"Language1",
"Language2",
"Language3",
"Linkage1",
"Linkage2",
"Literals",
"Loops",
"Macros",
Expand Down
2 changes: 2 additions & 0 deletions change_notes/2026-01-26-a3-1-1-extern-to-full.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- `A3-1-1` - `ViolationsOfOneDefinitionRule.ql`:
- The query previously would incorrectly allow cases where something was defined with `extern` and did not use the defined external linkage library to find external linkage. This change may result in the query finding more results. Additionally a typo has been fixed in the alert message which will cause the old alerts for this query to now show up as new ones.
67 changes: 5 additions & 62 deletions cpp/autosar/src/rules/A3-1-1/ViolationsOfOneDefinitionRule.ql
Original file line number Diff line number Diff line change
Expand Up @@ -20,67 +20,10 @@

import cpp
import codingstandards.cpp.autosar
import codingstandards.cpp.AcceptableHeader
import codingstandards.cpp.rules.violationsofonedefinitionrule.ViolationsOfOneDefinitionRule

predicate isInline(Function decl) {
exists(Specifier spec |
spec = decl.getASpecifier() and
(
spec.hasName("inline") or
spec.hasName("constexpr")
)
)
class ViolationsOfOneDefinitionRuleQuery extends ViolationsOfOneDefinitionRuleSharedQuery {
ViolationsOfOneDefinitionRuleQuery() {
this = IncludesPackage::violationsOfOneDefinitionRuleQuery()
}
}

predicate isExtern(FunctionDeclarationEntry decl) {
exists(string spec |
spec = decl.getASpecifier() and
spec = "extern"
)
}

from DeclarationEntry decl, string case, string name
where
(
//a non-inline/non-extern function defined in a header
exists(FunctionDeclarationEntry fn |
fn.isDefinition() and
not (
isInline(fn.getDeclaration())
or
isExtern(fn)
or
//any (defined) templates do not violate the ODR
fn.isFromUninstantiatedTemplate(_)
or
fn.isFromTemplateInstantiation(_) and
//except for specializations, those do violate ODR
not fn.isSpecialization()
or
fn.getDeclaration().isStatic()
) and
decl = fn and
case = "function"
)
or
//an non-const object defined in a header
exists(GlobalOrNamespaceVariable object |
object.hasDefinition() and
not (
object.isConstexpr()
or
object.isConst()
or
object.isStatic()
) and
decl = object.getDefinition() and
case = "object"
)
) and
not decl.getDeclaration().getNamespace().isAnonymous() and
decl.getFile() instanceof AcceptableHeader and
not isExcluded(decl, IncludesPackage::violationsOfOneDefinitionRuleQuery()) and
name = decl.getName()
select decl,
"Header file $@ contains " + case + " " + name + " that lead to One Defintion Rule violation.",
decl.getFile(), decl.getFile().getBaseName()

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp/common/test/rules/violationsofonedefinitionrule/ViolationsOfOneDefinitionRule.ql
26 changes: 0 additions & 26 deletions cpp/autosar/test/rules/A3-1-1/test.hpp

This file was deleted.

44 changes: 44 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/cpp/Linkage2.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
import cpp
import RuleMetadata
import codingstandards.cpp.exclusions.RuleMetadata

newtype Linkage2Query =
TViolationsOfOneDefinitionRuleMisraQuery() or
TInternalLinkageSpecifiedAppropriatelyQuery()

predicate isLinkage2QueryMetadata(Query query, string queryId, string ruleId, string category) {
query =
// `Query` instance for the `violationsOfOneDefinitionRuleMisra` query
Linkage2Package::violationsOfOneDefinitionRuleMisraQuery() and
queryId =
// `@id` for the `violationsOfOneDefinitionRuleMisra` query
"cpp/misra/violations-of-one-definition-rule-misra" and
ruleId = "RULE-6-2-4" and
category = "required"
or
query =
// `Query` instance for the `internalLinkageSpecifiedAppropriately` query
Linkage2Package::internalLinkageSpecifiedAppropriatelyQuery() and
queryId =
// `@id` for the `internalLinkageSpecifiedAppropriately` query
"cpp/misra/internal-linkage-specified-appropriately" and
ruleId = "RULE-6-5-2" and
category = "advisory"
}

module Linkage2Package {
Query violationsOfOneDefinitionRuleMisraQuery() {
//autogenerate `Query` type
result =
// `Query` type for `violationsOfOneDefinitionRuleMisra` query
TQueryCPP(TLinkage2PackageQuery(TViolationsOfOneDefinitionRuleMisraQuery()))
}

Query internalLinkageSpecifiedAppropriatelyQuery() {
//autogenerate `Query` type
result =
// `Query` type for `internalLinkageSpecifiedAppropriately` query
TQueryCPP(TLinkage2PackageQuery(TInternalLinkageSpecifiedAppropriatelyQuery()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import Invariants
import Iterators
import Lambdas
import Linkage1
import Linkage2
import Literals
import Loops
import Macros
Expand Down Expand Up @@ -98,6 +99,7 @@ newtype TCPPQuery =
TIteratorsPackageQuery(IteratorsQuery q) or
TLambdasPackageQuery(LambdasQuery q) or
TLinkage1PackageQuery(Linkage1Query q) or
TLinkage2PackageQuery(Linkage2Query q) or
TLiteralsPackageQuery(LiteralsQuery q) or
TLoopsPackageQuery(LoopsQuery q) or
TMacrosPackageQuery(MacrosQuery q) or
Expand Down Expand Up @@ -161,6 +163,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
isIteratorsQueryMetadata(query, queryId, ruleId, category) or
isLambdasQueryMetadata(query, queryId, ruleId, category) or
isLinkage1QueryMetadata(query, queryId, ruleId, category) or
isLinkage2QueryMetadata(query, queryId, ruleId, category) or
isLiteralsQueryMetadata(query, queryId, ruleId, category) or
isLoopsQueryMetadata(query, queryId, ruleId, category) or
isMacrosQueryMetadata(query, queryId, ruleId, category) or
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Provides a library with a `problems` predicate for the following issue:
* Placing the definitions of functions or objects that are non-inline and have
* external linkage can lead to violations of the ODR and can lead to undefined
* behaviour.
*/

import cpp
import codingstandards.cpp.Customizations
import codingstandards.cpp.Exclusions
import codingstandards.cpp.AcceptableHeader
import codingstandards.cpp.Linkage

predicate isInline(Function decl) {
exists(Specifier spec |
spec = decl.getASpecifier() and
(
spec.hasName("inline") or
spec.hasName("constexpr")
)
)
}

abstract class ViolationsOfOneDefinitionRuleSharedQuery extends Query { }

Query getQuery() { result instanceof ViolationsOfOneDefinitionRuleSharedQuery }

query predicate problems(DeclarationEntry decl, string message, File declFile, string secondmessage) {
exists(string case |
not isExcluded(decl, getQuery()) and
declFile = decl.getFile() and
secondmessage = decl.getFile().getBaseName() and
message =
"Header file $@ contains " + case + " " + decl.getName() +
" that lead to One Definition Rule violation." and
hasExternalLinkage(decl.getDeclaration()) and
(
//a non-inline/non-extern function defined in a header
exists(FunctionDeclarationEntry fn |
fn.isDefinition() and
not (
isInline(fn.getDeclaration())
or
//any (defined) templates do not violate the ODR
fn.isFromUninstantiatedTemplate(_)
or
fn.isFromTemplateInstantiation(_) and
//except for specializations, those do violate ODR
not fn.isSpecialization()
or
//static/nonstatic member functions should still not be defined (so do not exclude here)
fn.getDeclaration().isStatic() and not fn.getFunction() instanceof MemberFunction
) and
decl = fn and
case = "function"
)
or
//an non-const object defined in a header
exists(Variable object |
not (
object.isConstexpr()
or
object.isConst()
or
object.isStatic()
) and
decl = object.getDefinition() and
case = "object"
)
) and
not decl.getDeclaration().getNamespace().isAnonymous() and
decl.getFile() instanceof AcceptableHeader
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
| test.hpp:3:6:3:7 | definition of f1 | Header file $@ contains function f1 that lead to One Definition Rule violation. | test.hpp:0:0:0:0 | test.hpp | test.hpp |
| test.hpp:8:5:8:5 | definition of i | Header file $@ contains object i that lead to One Definition Rule violation. | test.hpp:0:0:0:0 | test.hpp | test.hpp |
| test.hpp:9:12:9:13 | definition of i1 | Header file $@ contains object i1 that lead to One Definition Rule violation. | test.hpp:0:0:0:0 | test.hpp | test.hpp |
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.violationsofonedefinitionrule.ViolationsOfOneDefinitionRule

class TestFileQuery extends ViolationsOfOneDefinitionRuleSharedQuery, TestQuery { }
26 changes: 26 additions & 0 deletions cpp/common/test/rules/violationsofonedefinitionrule/test.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
void f(); // COMPLIANT

void f1() {} // NON_COMPLIANT
inline void f2() {} // COMPLIANT

template <typename T> void f3(T){}; // COMPLIANT - implicitly inline

int i; // NON_COMPLIANT
extern int i1 = 1; // NON_COMPLIANT

constexpr auto i2{1}; // COMPLIANT - not external linkage

struct S {
int i; // COMPLIANT - no linkage
inline static const int i1{1}; // COMPLIANT - inline
};

class C {
static int m(); // COMPLIANT
int m1(); // COMPLIANT
};

int C::m() {} // NON_COMPLIANT[FALSE_NEGATIVE] - external linkage library
// issue/namespace of class not found
int C::m1() {} // NON_COMPLIANT[FALSE_NEGATIVE] - external linkage library
// issue/namespace of class not found
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @id cpp/misra/violations-of-one-definition-rule-misra
* @name RULE-6-2-4: A header file shall not contain definitions of functions or objects that are non-inline and have external linkage
* @description Placing the definitions of functions or objects that are non-inline and have
* external linkage can lead to violations of the ODR and can lead to undefined
* behaviour.
* @kind problem
* @precision very-high
* @problem.severity error
* @tags external/misra/id/rule-6-2-4
* correctness
* maintainability
* readability
* scope/single-translation-unit
* external/misra/enforcement/decidable
* external/misra/obligation/required
*/

import cpp
import codingstandards.cpp.misra
import codingstandards.cpp.rules.violationsofonedefinitionrule.ViolationsOfOneDefinitionRule

class ViolationsOfOneDefinitionRuleMisraQuery extends ViolationsOfOneDefinitionRuleSharedQuery {
ViolationsOfOneDefinitionRuleMisraQuery() {
this = Linkage2Package::violationsOfOneDefinitionRuleMisraQuery()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @id cpp/misra/internal-linkage-specified-appropriately
* @name RULE-6-5-2: Internal linkage should be specified appropriately
* @description Using certain specifiers or declaring entities with internal linkage in certain
* namespaces can lead to confusion as to the linkage of the entity and can cause code
* to be more difficult to read.
* @kind problem
* @precision very-high
* @problem.severity error
* @tags external/misra/id/rule-6-5-2
* correctness
* maintainability
* readability
* scope/single-translation-unit
* external/misra/enforcement/decidable
* external/misra/obligation/advisory
*/

import cpp
import codingstandards.cpp.misra
import codingstandards.cpp.Linkage
import codingstandards.cpp.types.Pointers

from DeclarationEntry decl, string message
where
not isExcluded(decl, Linkage2Package::internalLinkageSpecifiedAppropriatelyQuery()) and
hasInternalLinkage(decl.getDeclaration()) and
//exclusions as per rule for const and constexpr Variables
not decl.getDeclaration().(Variable).getUnderlyingType().isConst() and
not decl.getDeclaration().(Variable).getType().(PointerOrArrayType).isDeeplyConstBelow() and
not decl.getDeclaration().(Variable).isConstexpr() and
(
decl.hasSpecifier("static") and
(
decl.getDeclaration().getNamespace().isAnonymous() and
message = "Static specifier used in anonymous namespace."
or
not decl.getDeclaration().getNamespace().isAnonymous() and
message = "Static specifier used in non-anonymous namespace."
)
or
decl.hasSpecifier("extern") and
decl.getDeclaration().getNamespace().isAnonymous() and
message = "Extern specifier used in anonymous namespace."
)
select decl, message
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp/common/test/rules/violationsofonedefinitionrule/ViolationsOfOneDefinitionRule.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
| test.cpp:1:13:1:13 | declaration of f | Static specifier used in non-anonymous namespace. |
| test.cpp:5:13:5:14 | declaration of f2 | Extern specifier used in anonymous namespace. |
| test.cpp:8:12:8:13 | declaration of i1 | Extern specifier used in anonymous namespace. |
| test.cpp:9:12:9:13 | definition of i2 | Static specifier used in anonymous namespace. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-6-5-2/InternalLinkageSpecifiedAppropriately.ql
Loading
Loading