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
Original file line number Diff line number Diff line change
@@ -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.
18 changes: 9 additions & 9 deletions cpp/common/src/codingstandards/cpp/Linkage.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 |
Expand All @@ -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 |
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import Declarations2
import Declarations3
import Declarations4
import Declarations7
import Declarations8
import ExceptionSafety
import Exceptions1
import Exceptions2
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<TypesCompatibleConfig, interestedInFunctions/2>;

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()
41 changes: 41 additions & 0 deletions cpp/misra/src/rules/RULE-6-2-3/DuplicateTypeDefinitions.ql
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
@@ -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()
Original file line number Diff line number Diff line change
@@ -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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-6-2-3/DuplicateInlineFunctionDefinitions.ql
Original file line number Diff line number Diff line change
@@ -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<T> | Type 'TplRedefined<T>' is defined in files $@ and $@. | test.cpp:23:29:23:40 | definition of TplRedefined<T> | test.cpp | test2.cpp:23:29:23:40 | definition of TplRedefined<T> | 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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-6-2-3/DuplicateTypeDefinitions.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
| noncompliant_specialization.h:3:19:3:28 | Tpl1<long> | Template specialization 'Tpl1<long>' is declared in a different file than $@ and all specialized template arguments. | template.h:10:29:10:32 | Tpl1<T> | Tpl1<T> |
| noncompliant_specialization.h:4:19:4:38 | Tpl1<C2> | Template specialization 'Tpl1<C2>' is declared in a different file than $@ and all specialized template arguments. | template.h:10:29:10:32 | Tpl1<T> | Tpl1<T> |
| noncompliant_specialization.h:5:19:5:35 | Tpl1<C2> | Template specialization 'Tpl1<C2>' is declared in a different file than $@ and all specialized template arguments. | template.h:10:29:10:32 | Tpl1<T> | Tpl1<T> |
| noncompliant_specialization.h:7:19:7:34 | Tpl2<long, long> | Template specialization 'Tpl2<long, long>' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2<A, B> | Tpl2<A, B> |
| noncompliant_specialization.h:8:19:8:54 | Tpl2<C2, C2> | Template specialization 'Tpl2<C2, C2>' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2<A, B> | Tpl2<A, B> |
| noncompliant_specialization.h:9:19:9:48 | Tpl2<C2, C2> | Template specialization 'Tpl2<C2, C2>' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2<A, B> | Tpl2<A, B> |
| noncompliant_specialization.h:11:29:11:41 | Tpl2<long, T> | Template specialization 'Tpl2<long, T>' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2<A, B> | Tpl2<A, B> |
| noncompliant_specialization.h:12:29:12:48 | Tpl2<C1, T> | Template specialization 'Tpl2<C1, T>' is declared in a different file than $@ and all specialized template arguments. | template.h:11:41:11:44 | Tpl2<A, B> | Tpl2<A, B> |
| 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<<unnamed>> | Tpl3<<unnamed>> |
| noncompliant_specialization.h:15:19:15:31 | Tpl4<long, 0> | Template specialization 'Tpl4<long, 0>' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4<T, <unnamed>> | Tpl4<T, <unnamed>> |
| noncompliant_specialization.h:16:19:16:41 | Tpl4<C1, 1> | Template specialization 'Tpl4<C1, 1>' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4<T, <unnamed>> | Tpl4<T, <unnamed>> |
| noncompliant_specialization.h:17:19:17:38 | Tpl4<C1, 1> | Template specialization 'Tpl4<C1, 1>' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4<T, <unnamed>> | Tpl4<T, <unnamed>> |
| noncompliant_specialization.h:18:24:18:43 | Tpl4<C2, N> | Template specialization 'Tpl4<C2, N>' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4<T, <unnamed>> | Tpl4<T, <unnamed>> |
| noncompliant_specialization.h:19:29:19:38 | Tpl4<T, 2> | Template specialization 'Tpl4<T, 2>' is declared in a different file than $@ and all specialized template arguments. | template.h:13:34:13:37 | Tpl4<T, <unnamed>> | Tpl4<T, <unnamed>> |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-6-2-3/TemplateSpecializationWrongLocation.ql
9 changes: 9 additions & 0 deletions cpp/misra/test/rules/RULE-6-2-3/class.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef CLASS_H
#define CLASS_H

namespace class_h {
class C1 {};
class C2 {};
} // namespace class_h

#endif // CLASS_H
17 changes: 17 additions & 0 deletions cpp/misra/test/rules/RULE-6-2-3/compliant_specialization.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "class.h"
#include "template.h"

namespace compliant_h {
class C1 {};
} // namespace compliant_h

template <> class Tpl1<compliant_h::C1> {}; // COMPLIANT
template <> class Tpl2<compliant_h::C1, compliant_h::C1> {}; // COMPLIANT
template <> class Tpl2<template_h::C1, compliant_h::C1> {}; // COMPLIANT
template <> class Tpl2<class_h::C1, compliant_h::C1> {}; // COMPLIANT
template <> class Tpl2<compliant_h::C1, long> {}; // COMPLIANT

template <typename T> class Tpl2<T, compliant_h::C1> {}; // COMPLIANT

template <> class Tpl4<compliant_h::C1, 0> {}; // COMPLIANT
template <int N> class Tpl4<compliant_h::C1, N> {}; // COMPLIANT
19 changes: 19 additions & 0 deletions cpp/misra/test/rules/RULE-6-2-3/noncompliant_specialization.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "template.h"

template <> class Tpl1<long> {}; // NON_COMPLIANT
template <> class Tpl1<template_h::C2> {}; // NON_COMPLIANT
template <> class Tpl1<class_h::C2> {}; // NON_COMPLIANT

template <> class Tpl2<long, long> {}; // NON_COMPLIANT
template <> class Tpl2<template_h::C2, template_h::C2> {}; // NON_COMPLIANT
template <> class Tpl2<class_h::C2, class_h::C2> {}; // NON_COMPLIANT

template <typename T> class Tpl2<long, T> {}; // NON_COMPLIANT
template <typename T> class Tpl2<class_h::C1, T> {}; // NON_COMPLIANT

template <> class Tpl3<1> {}; // NON_COMPLIANT
template <> class Tpl4<long, 0> {}; // NON_COMPLIANT
template <> class Tpl4<template_h::C1, 1> {}; // NON_COMPLIANT
template <> class Tpl4<class_h::C1, 1> {}; // NON_COMPLIANT
template <int N> class Tpl4<class_h::C2, N> {}; // NON_COMPLIANT
template <typename T> class Tpl4<T, 2> {}; // NON_COMPLIANT
30 changes: 30 additions & 0 deletions cpp/misra/test/rules/RULE-6-2-3/template.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef TEMPLATE_H
#define TEMPLATE_H
#include "class.h"

namespace template_h {
class C1 {};
class C2 {};
} // namespace template_h

template <typename T> class Tpl1 {};
template <typename A, typename B> class Tpl2 {};
template <int> class Tpl3 {};
template <typename T, int> class Tpl4 {};

template <> class Tpl1<int> {}; // COMPLIANT
template <> class Tpl1<template_h::C1> {}; // COMPLIANT
template <> class Tpl1<class_h::C1> {}; // COMPLIANT

template <> class Tpl2<int, int> {}; // COMPLIANT
template <> class Tpl2<template_h::C1, template_h::C1> {}; // COMPLIANT
template <> class Tpl2<class_h::C1, class_h::C1> {}; // COMPLIANT

template <typename T> class Tpl2<int, T> {}; // COMPLIANT

template <> class Tpl3<0> {}; // COMPLIANT
template <> class Tpl4<int, 0> {}; // COMPLIANT
template <> class Tpl4<template_h::C1, 0> {}; // COMPLIANT
template <> class Tpl4<class_h::C1, 0> {}; // COMPLIANT

#endif // TEMPLATE_H
Loading
Loading