-
Notifications
You must be signed in to change notification settings - Fork 1.9k
C++: Add predicates to support C++23 multidimensional subscript operators #21126
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
Changes from all commits
647d11a
3907fc7
e0f8b12
4c3fb0c
9ceb091
72f1aa9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| category: feature | ||
| --- | ||
| * Predicates `getArrayOffset/1` and `getAnArrayOffset` have been added to the `OverloadedArrayExpr` class to support C++23 multidimensional subscript operators. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| --- | ||
| category: deprecated | ||
| --- | ||
| * The `OverloadedArrayExpr::getArrayOffset/0` predicate has been deprecated. Use `OverloadedArrayExpr::getArrayOffset/1` and `OverloadedArrayExpr::getAnArrayOffset` instead. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -387,10 +387,23 @@ class OverloadedArrayExpr extends FunctionCall { | |
|
|
||
| /** | ||
| * Gets the expression giving the index. | ||
| * | ||
| * DEPRECATED: Use getArrayOffset/1 instead. | ||
| */ | ||
| deprecated Expr getArrayOffset() { result = this.getArrayOffset(0) } | ||
|
|
||
| /** | ||
| * Gets the expression giving the nth index. | ||
| */ | ||
| Expr getArrayOffset() { | ||
| if exists(this.getQualifier()) then result = this.getChild(0) else result = this.getChild(1) | ||
| Expr getArrayOffset(int n) { | ||
| n >= 0 and | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I gather it is safe to assume there are no further children (i.e. that this won't return a result if
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the current extractor implementation it is. |
||
| if exists(this.getQualifier()) then result = this.getChild(n) else result = this.getChild(n + 1) | ||
| } | ||
|
|
||
| /** | ||
| * Gets an expression giving an index. | ||
| */ | ||
| Expr getAnArrayOffset() { result = this.getArrayOffset(_) } | ||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #-----| [CopyAssignmentOperator] __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) | ||
| #-----| <params>: | ||
| #-----| getParameter(0): [Parameter] (unnamed parameter 0) | ||
| #-----| Type = [LValueReferenceType] const __va_list_tag & | ||
| #-----| [MoveAssignmentOperator] __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) | ||
| #-----| <params>: | ||
| #-----| getParameter(0): [Parameter] (unnamed parameter 0) | ||
| #-----| Type = [RValueReferenceType] __va_list_tag && | ||
| test.cpp: | ||
| # 3| [CopyAssignmentOperator] S& S::operator=(S const&) | ||
| # 3| <params>: | ||
| #-----| getParameter(0): [Parameter] (unnamed parameter 0) | ||
| #-----| Type = [LValueReferenceType] const S & | ||
| # 3| [MoveAssignmentOperator] S& S::operator=(S&&) | ||
| # 3| <params>: | ||
| #-----| getParameter(0): [Parameter] (unnamed parameter 0) | ||
| #-----| Type = [RValueReferenceType] S && | ||
| # 5| [MemberFunction] int S::operator[](int, int) | ||
| # 5| <params>: | ||
| # 5| getParameter(0): [Parameter] i | ||
| # 5| Type = [IntType] int | ||
| # 5| getParameter(1): [Parameter] j | ||
| # 5| Type = [IntType] int | ||
| # 5| getEntryPoint(): [BlockStmt] { ... } | ||
| # 6| getStmt(0): [ReturnStmt] return ... | ||
| # 6| getExpr(): [ArrayExpr] access to array | ||
| # 6| Type = [IntType] int | ||
| # 6| ValueCategory = prvalue(load) | ||
| # 6| getArrayBase(): [ArrayExpr] access to array | ||
| # 6| Type = [ArrayType] int[2] | ||
| # 6| ValueCategory = lvalue | ||
| # 6| getArrayBase(): [ImplicitThisFieldAccess,PointerFieldAccess] xs | ||
| # 6| Type = [ArrayType] int[2][2] | ||
| # 6| ValueCategory = lvalue | ||
| # 6| getQualifier(): [ThisExpr] this | ||
| # 6| Type = [PointerType] S * | ||
| # 6| ValueCategory = prvalue(load) | ||
| # 6| getArrayOffset(): [VariableAccess] i | ||
| # 6| Type = [IntType] int | ||
| # 6| ValueCategory = prvalue(load) | ||
| #-----| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion | ||
| #-----| Type = [PointerType] int(*)[2] | ||
| #-----| ValueCategory = prvalue | ||
| # 6| getArrayOffset(): [VariableAccess] j | ||
| # 6| Type = [IntType] int | ||
| # 6| ValueCategory = prvalue(load) | ||
| # 6| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion | ||
| # 6| Type = [IntPointerType] int * | ||
| # 6| ValueCategory = prvalue | ||
| # 10| [TopLevelFunction] int foo(S) | ||
| # 10| <params>: | ||
| # 10| getParameter(0): [Parameter] s | ||
| # 10| Type = [Struct] S | ||
| # 10| getEntryPoint(): [BlockStmt] { ... } | ||
| # 11| getStmt(0): [ReturnStmt] return ... | ||
| # 11| getExpr(): [OverloadedArrayExpr] call to operator[] | ||
| # 11| Type = [IntType] int | ||
| # 11| ValueCategory = prvalue | ||
| # 11| getArrayBase(): [VariableAccess] s | ||
| # 11| Type = [Struct] S | ||
| # 11| ValueCategory = lvalue | ||
| # 11| getArrayOffset(0): [Literal] 1 | ||
| # 11| Type = [IntType] int | ||
| # 11| Value = [Literal] 1 | ||
| # 11| ValueCategory = prvalue | ||
| # 11| getArrayOffset(1): [Literal] 2 | ||
| # 11| Type = [IntType] int | ||
| # 11| Value = [Literal] 2 | ||
| # 11| ValueCategory = prvalue |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| semmle/code/cpp/PrintAST.ql |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // semmle-extractor-options: -std=c++23 | ||
|
|
||
| struct S { | ||
| int xs[2][2]; | ||
| int operator[](int i, int j) { | ||
| return xs[i][j]; | ||
| } | ||
| }; | ||
|
|
||
| int foo(S s) { | ||
| return s[1, 2]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation comment "Gets the expression giving the nth index" could be clearer. Consider specifying that
nis 0-indexed (i.e., n=0 gives the first index, n=1 gives the second index, etc.) to make the usage more explicit for users.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps one of these changes, both feels excessive, and frankly 0-based is generally the default for both C and CodeQL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the same 😄