Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
26 changes: 26 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode11.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
import cpp
import RuleMetadata
import codingstandards.cpp.exclusions.RuleMetadata

newtype DeadCode11Query = TPotentiallyErroneousContainerUsageQuery()

predicate isDeadCode11QueryMetadata(Query query, string queryId, string ruleId, string category) {
query =
// `Query` instance for the `potentiallyErroneousContainerUsage` query
DeadCode11Package::potentiallyErroneousContainerUsageQuery() and
queryId =
// `@id` for the `potentiallyErroneousContainerUsage` query
"cpp/misra/potentially-erroneous-container-usage" and
ruleId = "RULE-28-6-4" and
category = "required"
}

module DeadCode11Package {
Query potentiallyErroneousContainerUsageQuery() {
//autogenerate `Query` type
result =
// `Query` type for `potentiallyErroneousContainerUsage` query
TQueryCPP(TDeadCode11PackageQuery(TPotentiallyErroneousContainerUsageQuery()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Const
import Conversions
import Conversions2
import DeadCode
import DeadCode11
import DeadCode3
import DeadCode4
import Declarations
Expand Down Expand Up @@ -89,6 +90,7 @@ newtype TCPPQuery =
TConversionsPackageQuery(ConversionsQuery q) or
TConversions2PackageQuery(Conversions2Query q) or
TDeadCodePackageQuery(DeadCodeQuery q) or
TDeadCode11PackageQuery(DeadCode11Query q) or
TDeadCode3PackageQuery(DeadCode3Query q) or
TDeadCode4PackageQuery(DeadCode4Query q) or
TDeclarationsPackageQuery(DeclarationsQuery q) or
Expand Down Expand Up @@ -161,6 +163,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
isConversionsQueryMetadata(query, queryId, ruleId, category) or
isConversions2QueryMetadata(query, queryId, ruleId, category) or
isDeadCodeQueryMetadata(query, queryId, ruleId, category) or
isDeadCode11QueryMetadata(query, queryId, ruleId, category) or
isDeadCode3QueryMetadata(query, queryId, ruleId, category) or
isDeadCode4QueryMetadata(query, queryId, ruleId, category) or
isDeclarationsQueryMetadata(query, queryId, ruleId, category) or
Expand Down
25 changes: 25 additions & 0 deletions cpp/common/test/includes/standard-library/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,34 @@ template <class T> constexpr const T &min(const T &a, const T &b);
template <class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);

/** std::remove */
template <class ForwardIterator, class T>
ForwardIterator remove(ForwardIterator first, ForwardIterator last,
const T &value);
template <class ExecutionPolicy, class ForwardIterator, class T>
ForwardIterator remove(ExecutionPolicy &&policy, ForwardIterator first,
ForwardIterator last, const T &value);

/** std::remove_if */
template <class ForwardIterator, class Predicate>
ForwardIterator remove_if(ForwardIterator first, ForwardIterator last,
Predicate pred);
template <class ExecutionPolicy, class ForwardIterator, class Predicate>
ForwardIterator remove_if(ExecutionPolicy &&policy, ForwardIterator first,
ForwardIterator last, Predicate pred);

/** std::unique */
template <class ForwardIterator>
ForwardIterator unique(ForwardIterator first, ForwardIterator last);
template <class ExecutionPolicy, class ForwardIterator>
ForwardIterator unique(ExecutionPolicy &&policy, ForwardIterator first,
ForwardIterator last);
template <class ForwardIterator, class BinaryPredicate>
ForwardIterator unique(ForwardIterator first, ForwardIterator last,
BinaryPredicate pred);
template <class ExecutionPolicy, class ForwardIterator, class BinaryPredicate>
ForwardIterator unique(ExecutionPolicy &&policy, ForwardIterator first,
ForwardIterator last, BinaryPredicate pred);

template <class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last,
Expand Down
1 change: 1 addition & 0 deletions cpp/common/test/includes/standard-library/array
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define _GHLIBCPP_ARRAY
#include <iterator>
#include <string>
#include <empty.h>

// Note: a few features currently unused by tests are commented out
namespace std {
Expand Down
4 changes: 4 additions & 0 deletions cpp/common/test/includes/standard-library/deque.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define _GHLIBCPP_DEQUE
#include <iterator>
#include <string>
#include <initializer_list>
#include <empty.h>

namespace std {
template <class T, class Allocator = std::allocator<T>> class deque {
Expand All @@ -11,6 +13,8 @@ template <class T, class Allocator = std::allocator<T>> class deque {
typedef value_type &reference;
typedef const value_type &const_reference;

deque(std::initializer_list<T>, const Allocator & = Allocator());

typedef __iterator<T> iterator;
typedef __iterator<T> const_iterator;

Expand Down
21 changes: 21 additions & 0 deletions cpp/common/test/includes/standard-library/empty.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef _GHLIBCPP_EMPTY
#define _GHLIBCPP_EMPTY
#include <initializer_list>
#include <stddef.h>
/**
* Not intended to be used via #include <empty.h>, and not part of the public
* API.
*
* However, multiple libraries such as <array>, <deque>, etc define std::empty,
* so this is the singular header to define it in the test suite.
*/

namespace std {
template <class C> constexpr auto empty(const C &c) -> decltype(c.empty());

template <class T, size_t N> constexpr bool empty(const T (&)[N]) noexcept;

template <class T> constexpr bool empty(std::initializer_list<T>) noexcept;
} // namespace std

#endif // _GHLIBCPP_EMPTY
1 change: 1 addition & 0 deletions cpp/common/test/includes/standard-library/map
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "iterator.h"
#include <bits/stl_function.h>
#include <empty.h>

namespace std {

Expand Down
1 change: 1 addition & 0 deletions cpp/common/test/includes/standard-library/set
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "iterator.h"
#include <bits/stl_function.h>
#include <empty.h>

namespace std {
template <typename _Key, typename _Compare = std::less<_Key>,
Expand Down
1 change: 1 addition & 0 deletions cpp/common/test/includes/standard-library/string
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "iosfwd.h"
#include "iterator.h"
#include "stddef.h"
#include <empty.h>

namespace std {
template <class charT> struct char_traits {
Expand Down
1 change: 1 addition & 0 deletions cpp/common/test/includes/standard-library/string_view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#define _GHLIBCPP_STRING_VIEW

#include "stddef.h"
#include <empty.h>

namespace std {

Expand Down
6 changes: 6 additions & 0 deletions cpp/common/test/includes/standard-library/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define _GHLIBCPP_VECTOR
#include <iterator>
#include <string>
#include <empty.h>

namespace std {

Expand Down Expand Up @@ -52,6 +53,11 @@ template <class T, class Allocator = std::allocator<T>> class vector {
InputIterator last);
iterator insert(const_iterator position, initializer_list<T> il);

iterator erase(iterator position);
iterator erase(const_iterator position);
iterator erase(iterator first, iterator last);
iterator erase(const_iterator first, const_iterator last);

reference operator[](size_type n);
const_reference operator[](size_type n) const;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import cpp
import codingstandards.cpp.misra

predicate isRemoveOrUniqueCall(FunctionCall fc) {
exists(string name | name = fc.getTarget().getName() |
name = "remove" or
name = "remove_if" or
name = "unique"
) and
fc.getTarget().hasQualifiedName("std", _)
}

predicate isEmptyCall(FunctionCall fc) {
fc.getTarget().getName() = "empty" and
(
fc.getTarget().hasQualifiedName("std", "empty") or
fc.getTarget() instanceof MemberFunction
)
}

from FunctionCall fc, string message
where
not isExcluded(fc, DeadCode11Package::potentiallyErroneousContainerUsageQuery()) and
exists(ExprStmt es | es.getExpr() = fc) and
(
isRemoveOrUniqueCall(fc) and
message = "Result of call to '" + fc.getTarget().getName() + "' is not used."
or
isEmptyCall(fc) and
message = "Result of call to 'empty' is not used."
)
select fc, message
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
| test.cpp:10:3:10:13 | call to remove | Result of call to 'remove' is not used. |
| test.cpp:27:3:27:16 | call to remove_if | Result of call to 'remove_if' is not used. |
| test.cpp:49:3:49:13 | call to unique | Result of call to 'unique' is not used. |
| test.cpp:65:3:65:13 | call to unique | Result of call to 'unique' is not used. |
| test.cpp:82:6:82:10 | call to empty | Result of call to 'empty' is not used. |
| test.cpp:100:3:100:12 | call to empty | Result of call to 'empty' is not used. |
| test.cpp:117:3:117:13 | call to remove | Result of call to 'remove' is not used. |
| test.cpp:122:6:122:10 | call to empty | Result of call to 'empty' is not used. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-28-6-4/PotentiallyErroneousContainerUsage.ql
144 changes: 144 additions & 0 deletions cpp/misra/test/rules/RULE-28-6-4/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include <algorithm>
#include <cstdint>
#include <deque>
#include <string>
#include <vector>

// Test cases for std::remove
void test_remove_result_unused() {
std::vector<std::int32_t> v1 = {1, 2, 3, 2, 4};
std::remove(v1.begin(), v1.end(), 2); // NON_COMPLIANT
}

void test_remove_result_used() {
std::vector<std::int32_t> v1 = {1, 2, 3, 2, 4};
auto l1 = std::remove(v1.begin(), v1.end(), 2); // COMPLIANT
v1.erase(l1, v1.end());
}

void test_remove_result_used_in_erase() {
std::vector<std::int32_t> v1 = {1, 2, 3, 2, 4};
v1.erase(std::remove(v1.begin(), v1.end(), 2), v1.end()); // COMPLIANT
}

// Test cases for std::remove_if
void test_remove_if_result_unused() {
std::vector<std::int32_t> v1 = {1, 2, 3, 4, 5};
std::remove_if(v1.begin(), v1.end(),
[](std::int32_t l1) { return l1 % 2 == 0; }); // NON_COMPLIANT
}

void test_remove_if_result_used() {
std::vector<std::int32_t> v1 = {1, 2, 3, 4, 5};
auto l1 = std::remove_if(v1.begin(), v1.end(), [](std::int32_t l2) {
return l2 % 2 == 0;
}); // COMPLIANT
v1.erase(l1, v1.end());
}

void test_remove_if_result_used_in_erase() {
std::vector<std::int32_t> v1 = {1, 2, 3, 4, 5};
v1.erase(std::remove_if(v1.begin(), v1.end(),
[](std::int32_t l1) { return l1 % 2 == 0; }),
v1.end()); // COMPLIANT
}

// Test cases for std::unique
void test_unique_result_unused() {
std::vector<std::int32_t> v1 = {0, 0, 1, 1, 2, 2, 3, 3};
std::unique(v1.begin(), v1.end()); // NON_COMPLIANT
}

void test_unique_result_used() {
std::vector<std::int32_t> v1 = {0, 0, 1, 1, 2, 2, 3, 3};
auto l1 = std::unique(v1.begin(), v1.end()); // COMPLIANT
v1.erase(l1, v1.end());
}

void test_unique_result_used_in_erase() {
std::vector<std::int32_t> v1 = {0, 0, 1, 1, 2, 2, 3, 3};
v1.erase(std::unique(v1.begin(), v1.end()), v1.end()); // COMPLIANT
}

void test_unique_with_predicate_result_unused() {
std::vector<std::int32_t> v1 = {1, 2, 3, 4, 5, 6};
std::unique(v1.begin(), v1.end(), [](std::int32_t l1, std::int32_t l2) {
return (l1 % 2) == (l2 % 2);
}); // NON_COMPLIANT
}

void test_unique_with_predicate_result_used() {
std::vector<std::int32_t> v1 = {1, 2, 3, 4, 5, 6};
auto l1 =
std::unique(v1.begin(), v1.end(), [](std::int32_t l2, std::int32_t l3) {
return (l2 % 2) == (l3 % 2);
}); // COMPLIANT
v1.erase(l1, v1.end());
}

// Test cases for empty (member function)
void test_empty_member_result_unused() {
std::vector<std::int32_t> v1 = {1, 2, 3};
v1.empty(); // NON_COMPLIANT
}

void test_empty_member_result_used_in_condition() {
std::vector<std::int32_t> v1 = {1, 2, 3};
if (v1.empty()) { // COMPLIANT
v1.clear();
}
}

void test_empty_member_result_used_in_assignment() {
std::vector<std::int32_t> v1 = {1, 2, 3};
bool l1 = v1.empty(); // COMPLIANT
}

// Test cases for std::empty (non-member function)
void test_empty_nonmember_result_unused() {
std::vector<std::int32_t> v1 = {1, 2, 3};
std::empty(v1); // NON_COMPLIANT
}

void test_empty_nonmember_result_used_in_condition() {
std::vector<std::int32_t> v1 = {1, 2, 3};
if (!std::empty(v1)) { // COMPLIANT
v1.clear();
}
}

void test_empty_nonmember_result_used_in_assignment() {
std::vector<std::int32_t> v1 = {1, 2, 3};
bool l1 = std::empty(v1); // COMPLIANT
}

void test_remove_with_deque() {
std::deque<std::int32_t> d1 = {1, 2, 3, 2, 4};
std::remove(d1.begin(), d1.end(), 2); // NON_COMPLIANT
}

void test_empty_with_string() {
std::string s1 = "hello";
s1.empty(); // NON_COMPLIANT
}

void test_empty_with_string_compliant() {
std::string s1 = "hello";
if (s1.empty()) { // COMPLIANT
s1 = "default";
}
}

// Edge case: result stored but not used
void test_remove_result_stored_but_not_used() {
std::vector<std::int32_t> v1 = {1, 2, 3, 2, 4};
auto l1 = std::remove(v1.begin(), v1.end(), 2); // COMPLIANT
}

// Edge case: chaining operations
void test_remove_chained_operations() {
std::vector<std::int32_t> v1 = {1, 2, 3, 2, 4};
std::vector<std::int32_t> v2 = {5, 6, 7};
v1.erase(std::remove(v1.begin(), v1.end(), 2), v1.end()); // COMPLIANT
v2.erase(std::remove(v2.begin(), v2.end(), 6), v2.end()); // COMPLIANT
}
Loading
Loading