diff --git a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll index cf8c2ad5998..4dd45a5bf42 100644 --- a/cpp/ql/src/semmle/code/cpp/exprs/Access.qll +++ b/cpp/ql/src/semmle/code/cpp/exprs/Access.qll @@ -226,6 +226,29 @@ class ImplicitThisFieldAccess extends FieldAccess { ImplicitThisFieldAccess() { not exists(this.getQualifier()) } } +/** + * A C++ _pointer to non-static data member_ literal. For example, `&C::x` is + * an expression that refers to field `x` of class `C`. If the type of that + * field is `int`, then `&C::x` ought to have type `int C::*`. It is currently + * modeled in QL as having type `int`. + * + * See [dcl.mptr] in the C++17 standard or see + * https://en.cppreference.com/w/cpp/language/pointer#Pointers_to_data_members. + */ +class PointerToFieldLiteral extends ImplicitThisFieldAccess { + PointerToFieldLiteral() { + // The extractor currently emits a pointer-to-field literal as a field + // access without a qualifier. The only other unqualified field accesses it + // emits are for compiler-generated constructors and destructors. When we + // filter those out, there are only pointer-to-field literals left. + not this.isCompilerGenerated() + } + + override predicate isConstant() { any() } + + override string getCanonicalQLClass() { result = "PointerToFieldLiteral" } +} + /** * A C/C++ function access expression. */ diff --git a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected b/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected index d1839e8a79a..00cdd21f9ed 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/drawDifferent.expected @@ -1,26 +1,3 @@ -| pointer_to_member__pmIsConst_extractor | false | 15698 | 15698 | pmIsConst | -| pointer_to_member__pmIsConst_extractor | false | 15724 | 15724 | declaration | -| pointer_to_member__pmIsConst_extractor | false | 15726 | 15726 | return ... | -| pointer_to_member__pmIsConst_extractor | false | 15728 | 15728 | { ... } | -| pointer_to_member__pmIsConst_extractor | false | 15731 | 15731 | {...} | -| pointer_to_member__pmIsConst_extractor | false | 15734 | 15734 | x1 | -| pointer_to_member__pmIsConst_extractor | false | 15735 | 15735 | initializer for pms | -| pointer_to_member__pmIsConst_extractor | true | 15724 | 15726 | | -| pointer_to_member__pmIsConst_extractor | true | 15726 | 15698 | | -| pointer_to_member__pmIsConst_extractor | true | 15728 | 15724 | | -| pointer_to_member__pmIsConst_ql | false | 15698 | 15698 | pmIsConst | -| pointer_to_member__pmIsConst_ql | false | 15724 | 15724 | declaration | -| pointer_to_member__pmIsConst_ql | false | 15726 | 15726 | return ... | -| pointer_to_member__pmIsConst_ql | false | 15728 | 15728 | { ... } | -| pointer_to_member__pmIsConst_ql | false | 15731 | 15731 | {...} | -| pointer_to_member__pmIsConst_ql | false | 15734 | 15734 | x1 | -| pointer_to_member__pmIsConst_ql | false | 15735 | 15735 | initializer for pms | -| pointer_to_member__pmIsConst_ql | true | 15724 | 15735 | | -| pointer_to_member__pmIsConst_ql | true | 15726 | 15698 | | -| pointer_to_member__pmIsConst_ql | true | 15728 | 15724 | | -| pointer_to_member__pmIsConst_ql | true | 15731 | 15726 | | -| pointer_to_member__pmIsConst_ql | true | 15734 | 15731 | | -| pointer_to_member__pmIsConst_ql | true | 15735 | 15734 | | | staticlocals__staticlocals_f2_extractor | false | 22465 | 22465 | f2 | | staticlocals__staticlocals_f2_extractor | false | 22470 | 22470 | declaration | | staticlocals__staticlocals_f2_extractor | false | 22472 | 22472 | declaration | diff --git a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected b/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected index c940eaaa466..ffb4863ef4c 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/tellDifferent.expected @@ -1,8 +1,3 @@ -| pointer_to_member__pmIsConst | pointer_to_member.cpp:33:3:35:22 | declaration | pointer_to_member.cpp:35:11:35:21 | initializer for pms | Standard edge, only from QL | -| pointer_to_member__pmIsConst | pointer_to_member.cpp:33:3:35:22 | declaration | pointer_to_member.cpp:36:1:36:1 | return ... | Standard edge, only from extractor | -| pointer_to_member__pmIsConst | pointer_to_member.cpp:35:11:35:21 | initializer for pms | pointer_to_member.cpp:35:13:35:19 | x1 | Standard edge, only from QL | -| pointer_to_member__pmIsConst | pointer_to_member.cpp:35:11:35:21 | {...} | pointer_to_member.cpp:36:1:36:1 | return ... | Standard edge, only from QL | -| pointer_to_member__pmIsConst | pointer_to_member.cpp:35:13:35:19 | x1 | pointer_to_member.cpp:35:11:35:21 | {...} | Standard edge, only from QL | | staticlocals__staticlocals_f2 | file://:0:0:0:0 | call to C | staticlocals.cpp:30:1:30:1 | return ... | Standard edge, only from QL | | staticlocals__staticlocals_f2 | file://:0:0:0:0 | initializer for c | file://:0:0:0:0 | call to C | Standard edge, only from QL | | staticlocals__staticlocals_f2 | staticlocals.cpp:29:5:29:17 | declaration | file://:0:0:0:0 | initializer for c | Standard edge, only from QL |