Skip to content

Resolve 371 #538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions change_notes/2024-02-16-fix-fps-a5-1-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- `A5-1-1` - `LiteralValueUsedOutsideTypeInit.ql`:
- Address FP reported in #371. Exclude literals generated by uses of constexpr variables.
- Exclude literals used in class template instantiations.
- Update the alert message to adhere to the style-guide.
10 changes: 6 additions & 4 deletions cpp/autosar/src/rules/A5-1-1/LiteralValueUsedOutsideTypeInit.ql
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ where
// Aggregate literal
not l = any(ArrayOrVectorAggregateLiteral aal).getAnElementExpr(_).getAChild*() and
// Ignore x - 1 expressions
not exists(SubExpr se | se.getRightOperand() = l and l.getValue() = "1")
select l,
"Literal value " + getTruncatedLiteralText(l) + " used outside of type initialization " +
l.getAPrimaryQlClass()
not exists(SubExpr se | se.getRightOperand() = l and l.getValue() = "1") and
not l instanceof CompileTimeComputedIntegralLiteral and
// Exclude literals to instantiate a class template per example in the standard
// where an type of std::array is intialized with size 5.
not l = any(ClassTemplateInstantiation cti).getATemplateArgument()
select l, "Literal value '" + getTruncatedLiteralText(l) + "' used outside of type initialization."
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
| test.cpp:5:9:5:25 | constant string | Literal value "constant string" used outside of type initialization StringLiteral |
| test.cpp:14:23:14:25 | 100 | Literal value 100 used outside of type initialization Literal |
| test.cpp:54:7:54:7 | 1 | Literal value 1 used outside of type initialization Literal |
| test.cpp:75:23:75:28 | test | Literal value "test" used outside of type initialization StringLiteral |
| test.cpp:76:19:76:28 | not okay | Literal value "not okay" used outside of type initialization StringLiteral |
| test.cpp:5:9:5:25 | constant string | Literal value '"constant string"' used outside of type initialization. |
| test.cpp:14:23:14:25 | 100 | Literal value '100' used outside of type initialization. |
| test.cpp:54:7:54:7 | 1 | Literal value '1' used outside of type initialization. |
| test.cpp:75:23:75:28 | test | Literal value '"test"' used outside of type initialization. |
| test.cpp:76:19:76:28 | not okay | Literal value '"not okay"' used outside of type initialization. |
| test.cpp:104:8:104:8 | 4 | Literal value '4' used outside of type initialization. |
| test.cpp:104:8:104:8 | 4 | Literal value '4' used outside of type initialization. |
| test.cpp:104:8:104:8 | 4 | Literal value '4' used outside of type initialization. |
24 changes: 23 additions & 1 deletion cpp/autosar/test/rules/A5-1-1/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,32 @@ void test_not_wrapper_stream(std::ostream &os, const char *str) noexcept {
#define MACRO_LOG(test_str) \
do { \
struct test_struct { \
static const char *get_str() { return static_cast<char *>(test_str); } \
static const char *get_str() { \
return static_cast<const char *>(test_str); \
} \
}; \
} while (false)

void f() {
MACRO_LOG("test"); // COMPLIANT - exclusion
}

template <typename T> struct S1 { static constexpr size_t value(); };

template <> struct S1<int> {
static constexpr size_t value() { return sizeof(int); };
};

constexpr size_t g1 = S1<int>::value();
constexpr size_t f1() { return sizeof(int); }

template <typename T, int size> struct S2 {
T m1[size]; // COMPLIANT
T m2[4]; // NON_COMPLIANT
};

void test_fp_reported_in_371() {
struct S2<int, 1> l1; // COMPLIANT
struct S2<int, g1> l2; // COMPLIANT
struct S2<int, f1()> l3; // COMPLIANT
}
19 changes: 19 additions & 0 deletions cpp/common/src/codingstandards/cpp/Literals.qll
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,22 @@ class Utf16StringLiteral extends StringLiteral {
class Utf32StringLiteral extends StringLiteral {
Utf32StringLiteral() { this.getValueText().regexpMatch("(?s)\\s*U\".*") }
}

/**
* A literal resulting from the use of a constexpr
* variable, or macro expansion.
*/
class CompileTimeComputedIntegralLiteral extends Literal {
CompileTimeComputedIntegralLiteral() {
this.getUnspecifiedType() instanceof IntegralType and
not this.getUnspecifiedType() instanceof BoolType and
not this.getUnspecifiedType() instanceof CharType and
// In some cases we still type char constants like '.' as int
not this.getValueText().trim().matches("'%'") and
not this.getValueText()
.trim()
.regexpMatch("([0-9][0-9']*|0[xX][0-9a-fA-F']+|0b[01']+)[uU]?([lL]{1,2}|[zZ])?") and
// Exclude class field initializers whose value text equals the initializer expression, e.g., `x(0)`
not any(ConstructorFieldInit cfi).getExpr() = this
}
}