Skip to content

Commit f381feb

Browse files
Initial draft for non-const function objects.
1 parent b0e343f commit f381feb

File tree

13 files changed

+325
-1
lines changed

13 files changed

+325
-1
lines changed

cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import Representation
6161
import Scope
6262
import SideEffects1
6363
import SideEffects2
64+
import SideEffects6
6465
import SmartPointers1
6566
import SmartPointers2
6667
import Statements
@@ -134,6 +135,7 @@ newtype TCPPQuery =
134135
TScopePackageQuery(ScopeQuery q) or
135136
TSideEffects1PackageQuery(SideEffects1Query q) or
136137
TSideEffects2PackageQuery(SideEffects2Query q) or
138+
TSideEffects6PackageQuery(SideEffects6Query q) or
137139
TSmartPointers1PackageQuery(SmartPointers1Query q) or
138140
TSmartPointers2PackageQuery(SmartPointers2Query q) or
139141
TStatementsPackageQuery(StatementsQuery q) or
@@ -207,6 +209,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
207209
isScopeQueryMetadata(query, queryId, ruleId, category) or
208210
isSideEffects1QueryMetadata(query, queryId, ruleId, category) or
209211
isSideEffects2QueryMetadata(query, queryId, ruleId, category) or
212+
isSideEffects6QueryMetadata(query, queryId, ruleId, category) or
210213
isSmartPointers1QueryMetadata(query, queryId, ruleId, category) or
211214
isSmartPointers2QueryMetadata(query, queryId, ruleId, category) or
212215
isStatementsQueryMetadata(query, queryId, ruleId, category) or
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype SideEffects6Query =
7+
TPredicateWithPersistentSideEffectsQuery() or
8+
TNonConstPredicateFunctionObjectQuery()
9+
10+
predicate isSideEffects6QueryMetadata(Query query, string queryId, string ruleId, string category) {
11+
query =
12+
// `Query` instance for the `predicateWithPersistentSideEffects` query
13+
SideEffects6Package::predicateWithPersistentSideEffectsQuery() and
14+
queryId =
15+
// `@id` for the `predicateWithPersistentSideEffects` query
16+
"cpp/misra/predicate-with-persistent-side-effects" and
17+
ruleId = "RULE-28-3-1" and
18+
category = "required"
19+
or
20+
query =
21+
// `Query` instance for the `nonConstPredicateFunctionObject` query
22+
SideEffects6Package::nonConstPredicateFunctionObjectQuery() and
23+
queryId =
24+
// `@id` for the `nonConstPredicateFunctionObject` query
25+
"cpp/misra/non-const-predicate-function-object" and
26+
ruleId = "RULE-28-3-1" and
27+
category = "required"
28+
}
29+
30+
module SideEffects6Package {
31+
Query predicateWithPersistentSideEffectsQuery() {
32+
//autogenerate `Query` type
33+
result =
34+
// `Query` type for `predicateWithPersistentSideEffects` query
35+
TQueryCPP(TSideEffects6PackageQuery(TPredicateWithPersistentSideEffectsQuery()))
36+
}
37+
38+
Query nonConstPredicateFunctionObjectQuery() {
39+
//autogenerate `Query` type
40+
result =
41+
// `Query` type for `nonConstPredicateFunctionObject` query
42+
TQueryCPP(TSideEffects6PackageQuery(TNonConstPredicateFunctionObjectQuery()))
43+
}
44+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import cpp
2+
private import codingstandards.cpp.StdNamespace
3+
private import codingstandards.cpp.types.Templates
4+
private import semmle.code.cpp.dataflow.new.DataFlow
5+
6+
Namespace getTemplateParameterNamespace(TypeTemplateParameter param) {
7+
exists(Declaration decl |
8+
param = decl.(TemplateClass).getATemplateArgument() or
9+
param = decl.(TemplateVariable).getATemplateArgument() or
10+
param = decl.(TemplateFunction).getATemplateArgument()
11+
|
12+
result = decl.getNamespace()
13+
)
14+
}
15+
16+
class PredicateType extends TypeTemplateParameter {
17+
PredicateType() {
18+
this.getName().matches(["%Compare%", "%Predicate%"]) and
19+
getTemplateParameterNamespace(this) instanceof StdNS
20+
}
21+
22+
Type getASubstitutedType(Substitution sub) { result = sub.getSubstitutedTypeForParameter(this) }
23+
}
24+
25+
class PredicateFunctionObject extends Class {
26+
PredicateType pred;
27+
Function operator;
28+
Substitution sub;
29+
30+
PredicateFunctionObject() {
31+
this = pred.getASubstitutedType(sub) and
32+
operator.getDeclaringType() = this and
33+
operator.getName() = "operator()"
34+
}
35+
36+
PredicateType getPredicateType() { result = pred }
37+
38+
Function getCallOperator() { result = operator }
39+
40+
Substitution getSubstitution() { result = sub }
41+
}
42+
43+
class PredicateFunctionPointerUse extends FunctionAccess {
44+
Expr functionPointerArgument;
45+
FunctionCall templateFunctionCall;
46+
FunctionTemplateInstantiation instantiation;
47+
Substitution sub;
48+
PredicateType pred;
49+
Parameter parameter;
50+
int index;
51+
52+
PredicateFunctionPointerUse() {
53+
functionPointerArgument = templateFunctionCall.getArgument(index) and
54+
templateFunctionCall.getTarget() = instantiation and
55+
parameter = instantiation.getParameter(index) and
56+
sub.asFunctionSubstitution() = instantiation and
57+
parameter.getType() = sub.getSubstitutedTypeForParameter(pred) and
58+
exists(DataFlow::Node func, DataFlow::Node arg |
59+
func.asExpr() = this and
60+
arg.asExpr() = functionPointerArgument and
61+
DataFlow::localFlow(func, arg)
62+
)
63+
}
64+
65+
PredicateType getPredicateType() { result = pred }
66+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import cpp
2+
3+
private newtype TSubstitution =
4+
TClassSubstitution(ClassTemplateInstantiation cti) or
5+
TFunctionSubstitution(FunctionTemplateInstantiation fti) or
6+
TVariableSubstitution(VariableTemplateInstantiation vti)
7+
8+
class Substitution extends TSubstitution {
9+
ClassTemplateInstantiation asClassSubstitution() { this = TClassSubstitution(result) }
10+
11+
FunctionTemplateInstantiation asFunctionSubstitution() { this = TFunctionSubstitution(result) }
12+
13+
VariableTemplateInstantiation asVariableSubstitution() { this = TVariableSubstitution(result) }
14+
15+
TypeTemplateParameter getTemplateParameter(int index) {
16+
result = this.asClassSubstitution().getTemplate().getTemplateArgument(index) or
17+
result = this.asFunctionSubstitution().getTemplate().getTemplateArgument(index) or
18+
result = this.asVariableSubstitution().getTemplate().getTemplateArgument(index)
19+
}
20+
21+
Type getSubstitutedType(int index) {
22+
result = this.asClassSubstitution().getTemplateArgument(index) or
23+
result = this.asFunctionSubstitution().getTemplateArgument(index) or
24+
result = this.asVariableSubstitution().getTemplateArgument(index)
25+
}
26+
27+
Type getSubstitutedTypeForParameter(TypeTemplateParameter param) {
28+
exists(int idx |
29+
this.getTemplateParameter(idx) = param and
30+
result = this.getSubstitutedType(idx)
31+
)
32+
}
33+
34+
string toString() {
35+
result = this.asClassSubstitution().toString() or
36+
result = this.asFunctionSubstitution().toString() or
37+
result = this.asVariableSubstitution().toString()
38+
}
39+
40+
Locatable getASubstitutionSite() {
41+
result.(TypeMention).getMentionedType() = this.asClassSubstitution()
42+
or
43+
result.(Call).getTarget() = this.asFunctionSubstitution()
44+
or
45+
result.(FunctionAccess).getTarget() = this.asFunctionSubstitution()
46+
or
47+
result.(VariableAccess).getTarget() = this.asVariableSubstitution()
48+
}
49+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @id cpp/misra/non-const-predicate-function-object
3+
* @name RULE-28-3-1: Predicates shall not have persistent side effects
4+
* @description Much of the behavior of predicates is implementation defined, such as how and when
5+
* it is invoked with which argument values, and if it is copied or moved. Therefore,
6+
* predicate function objects should be declared const.
7+
* @kind problem
8+
* @precision very-high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-28-3-1
11+
* scope/system
12+
* correctness
13+
* maintainability
14+
* portability
15+
* external/misra/enforcement/undecidable
16+
* external/misra/obligation/required
17+
*/
18+
19+
import cpp
20+
import codingstandards.cpp.misra
21+
import codingstandards.cpp.SideEffect
22+
import codingstandards.cpp.types.Predicate
23+
24+
from MemberFunction callOperator, PredicateFunctionObject obj, Locatable usageSite
25+
where
26+
not isExcluded([callOperator, usageSite],
27+
SideEffects6Package::nonConstPredicateFunctionObjectQuery()) and
28+
obj.getSubstitution().getASubstitutionSite() = usageSite and
29+
callOperator = obj.getCallOperator() and
30+
not callOperator instanceof ConstMemberFunction
31+
select usageSite, "Predicate usage of $@ has $@", callOperator.getDeclaringType(),
32+
"callable object " + callOperator.getDeclaringType().getName(), callOperator,
33+
"non const operator()."
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @id cpp/misra/predicate-with-persistent-side-effects
3+
* @name RULE-28-3-1: Predicates shall not have persistent side effects
4+
* @description Much of the behavior of predicates is implementation defined, such as how and when
5+
* it is invoked with which argument values, and if it is copied or moved. Therefore,
6+
* persistent side effects in a predicate cannot be relied upon and should not occur.
7+
* @kind problem
8+
* @precision very-high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-28-3-1
11+
* scope/system
12+
* correctness
13+
* maintainability
14+
* portability
15+
* external/misra/enforcement/undecidable
16+
* external/misra/obligation/required
17+
*/
18+
19+
import cpp
20+
import codingstandards.cpp.misra
21+
import codingstandards.cpp.SideEffect
22+
import codingstandards.cpp.types.Predicate
23+
24+
predicate functionHasSideEffect(Function f) {
25+
hasExternalOrGlobalSideEffectInFunction(f)
26+
}
27+
28+
predicate isPredicateObject(PredicateFunctionObject obj, PredicateType pred, Locatable usageSite, Function callOperator) {
29+
obj.getSubstitution().getASubstitutionSite() = usageSite and
30+
pred = obj.getPredicateType() and
31+
callOperator = obj.getCallOperator()
32+
}
33+
34+
predicate isPredicateFunctionPointerUse(PredicateFunctionPointerUse predPtrUse, PredicateType pred, Function func) {
35+
pred = predPtrUse.getPredicateType() and
36+
func = predPtrUse.getTarget()
37+
}
38+
39+
where
40+
not isExcluded(x, SideEffects6Package::predicateWithPersistentSideEffectsQuery()) and
41+
select
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| test.cpp:21:3:21:11 | call to sort | Predicate usage of $@ has $@ | test.cpp:10:8:10:9 | F1 | callable object F1 | test.cpp:11:8:11:17 | operator() | non const operator(). |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-28-3-1/NonConstPredicateFunctionObject.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No expected results have yet been specified
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-28-3-1/PredicateWithPersistentSideEffects.ql

0 commit comments

Comments
 (0)