Skip to content

Commit b72d892

Browse files
authored
Merge pull request github#13762 from jketema/fun-qual
C++: Handle `FunctionAccess`es with qualifiers
2 parents d41d2bc + aad094b commit b72d892

File tree

7 files changed

+380
-3
lines changed

7 files changed

+380
-3
lines changed

cpp/ql/lib/semmle/code/cpp/PrintAST.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,8 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
741741
or
742742
expr.(VariableAccess).getQualifier() = ele and pred = "getQualifier()"
743743
or
744+
expr.(FunctionAccess).getQualifier() = ele and pred = "getQualifier()"
745+
or
744746
exists(Field f |
745747
expr.(ClassAggregateLiteral).getAFieldExpr(f) = ele and
746748
pred = "getAFieldExpr(" + f.toString() + ")"

cpp/ql/lib/semmle/code/cpp/exprs/Access.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ class FunctionAccess extends Access, @routineexpr {
368368
/** Gets the accessed function. */
369369
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
370370

371+
/**
372+
* Gets the expression generating the function being accessed.
373+
*/
374+
Expr getQualifier() { this.getChild(-1) = result }
375+
371376
/** Gets a textual representation of this function access. */
372377
override string toString() {
373378
if exists(this.getTarget())

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -991,9 +991,19 @@ class TranslatedStructuredBindingVariableAccess extends TranslatedNonConstantExp
991991
class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
992992
override FunctionAccess expr;
993993

994-
override TranslatedElement getChild(int id) { none() }
994+
override TranslatedElement getChild(int id) {
995+
id = 0 and result = this.getQualifier() // Might not exist
996+
}
995997

996-
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
998+
final TranslatedExpr getQualifier() {
999+
result = getTranslatedExpr(expr.getQualifier().getFullyConverted())
1000+
}
1001+
1002+
override Instruction getFirstInstruction() {
1003+
if exists(this.getQualifier())
1004+
then result = this.getQualifier().getFirstInstruction()
1005+
else result = this.getInstruction(OnlyInstructionTag())
1006+
}
9971007

9981008
override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
9991009

@@ -1014,7 +1024,9 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
10141024
result = expr.getTarget()
10151025
}
10161026

1017-
override Instruction getChildSuccessor(TranslatedElement child) { none() }
1027+
override Instruction getChildSuccessor(TranslatedElement child) {
1028+
child = this.getQualifier() and result = this.getInstruction(OnlyInstructionTag())
1029+
}
10181030
}
10191031

10201032
/**

cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14731,6 +14731,163 @@ ir.cpp:
1473114731
# 1970| Type = [IntType] int
1473214732
# 1970| ValueCategory = prvalue(load)
1473314733
# 1971| getStmt(2): [ReturnStmt] return ...
14734+
# 1973| [CopyAssignmentOperator] ValCat& ValCat::operator=(ValCat const&)
14735+
# 1973| <params>:
14736+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
14737+
#-----| Type = [LValueReferenceType] const ValCat &
14738+
# 1973| [MoveAssignmentOperator] ValCat& ValCat::operator=(ValCat&&)
14739+
# 1973| <params>:
14740+
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
14741+
#-----| Type = [RValueReferenceType] ValCat &&
14742+
# 1974| [MemberFunction] ValCat& ValCat::lvalue()
14743+
# 1974| <params>:
14744+
# 1975| [MemberFunction] ValCat&& ValCat::xvalue()
14745+
# 1975| <params>:
14746+
# 1976| [MemberFunction] ValCat ValCat::prvalue()
14747+
# 1976| <params>:
14748+
# 1979| [TopLevelFunction] void value_category_test()
14749+
# 1979| <params>:
14750+
# 1979| getEntryPoint(): [BlockStmt] { ... }
14751+
# 1980| getStmt(0): [DeclStmt] declaration
14752+
# 1980| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
14753+
# 1980| Type = [Struct] ValCat
14754+
# 1982| getStmt(1): [ExprStmt] ExprStmt
14755+
# 1982| getExpr(): [AssignExpr] ... = ...
14756+
# 1982| Type = [Struct] ValCat
14757+
# 1982| ValueCategory = lvalue
14758+
# 1982| getLValue(): [FunctionCall] call to lvalue
14759+
# 1982| Type = [LValueReferenceType] ValCat &
14760+
# 1982| ValueCategory = prvalue
14761+
# 1982| getQualifier(): [VariableAccess] c
14762+
# 1982| Type = [Struct] ValCat
14763+
# 1982| ValueCategory = lvalue
14764+
# 1982| getRValue(): [ClassAggregateLiteral] {...}
14765+
# 1982| Type = [Struct] ValCat
14766+
# 1982| ValueCategory = prvalue
14767+
# 1982| getLValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
14768+
# 1982| Type = [Struct] ValCat
14769+
# 1982| ValueCategory = lvalue
14770+
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
14771+
#-----| Type = [Struct] ValCat
14772+
#-----| ValueCategory = prvalue(load)
14773+
# 1983| getStmt(2): [ExprStmt] ExprStmt
14774+
# 1983| getExpr(): [AssignExpr] ... = ...
14775+
# 1983| Type = [Struct] ValCat
14776+
# 1983| ValueCategory = lvalue
14777+
# 1983| getLValue(): [FunctionCall] call to xvalue
14778+
# 1983| Type = [RValueReferenceType] ValCat &&
14779+
# 1983| ValueCategory = prvalue
14780+
# 1983| getQualifier(): [VariableAccess] c
14781+
# 1983| Type = [Struct] ValCat
14782+
# 1983| ValueCategory = lvalue
14783+
# 1983| getRValue(): [ClassAggregateLiteral] {...}
14784+
# 1983| Type = [Struct] ValCat
14785+
# 1983| ValueCategory = prvalue
14786+
# 1983| getLValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
14787+
# 1983| Type = [Struct] ValCat
14788+
# 1983| ValueCategory = lvalue
14789+
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
14790+
#-----| Type = [Struct] ValCat
14791+
#-----| ValueCategory = prvalue(load)
14792+
# 1984| getStmt(3): [ExprStmt] ExprStmt
14793+
# 1984| getExpr(): [AssignExpr] ... = ...
14794+
# 1984| Type = [Struct] ValCat
14795+
# 1984| ValueCategory = lvalue
14796+
# 1984| getLValue(): [FunctionCall] call to prvalue
14797+
# 1984| Type = [Struct] ValCat
14798+
# 1984| ValueCategory = prvalue
14799+
# 1984| getQualifier(): [VariableAccess] c
14800+
# 1984| Type = [Struct] ValCat
14801+
# 1984| ValueCategory = lvalue
14802+
# 1984| getRValue(): [ClassAggregateLiteral] {...}
14803+
# 1984| Type = [Struct] ValCat
14804+
# 1984| ValueCategory = prvalue
14805+
# 1984| getLValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
14806+
# 1984| Type = [Struct] ValCat
14807+
# 1984| ValueCategory = lvalue
14808+
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
14809+
#-----| Type = [Struct] ValCat
14810+
#-----| ValueCategory = prvalue(load)
14811+
# 1985| getStmt(4): [ExprStmt] ExprStmt
14812+
# 1985| getExpr(): [AssignExpr] ... = ...
14813+
# 1985| Type = [Struct] ValCat
14814+
# 1985| ValueCategory = lvalue
14815+
# 1985| getLValue(): [FunctionCall] call to lvalue
14816+
# 1985| Type = [LValueReferenceType] ValCat &
14817+
# 1985| ValueCategory = prvalue
14818+
# 1985| getRValue(): [ClassAggregateLiteral] {...}
14819+
# 1985| Type = [Struct] ValCat
14820+
# 1985| ValueCategory = prvalue
14821+
# 1985| getLValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
14822+
# 1985| Type = [Struct] ValCat
14823+
# 1985| ValueCategory = lvalue
14824+
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
14825+
#-----| Type = [Struct] ValCat
14826+
#-----| ValueCategory = prvalue(load)
14827+
# 1986| getStmt(5): [ExprStmt] ExprStmt
14828+
# 1986| getExpr(): [AssignExpr] ... = ...
14829+
# 1986| Type = [Struct] ValCat
14830+
# 1986| ValueCategory = lvalue
14831+
# 1986| getLValue(): [FunctionCall] call to xvalue
14832+
# 1986| Type = [RValueReferenceType] ValCat &&
14833+
# 1986| ValueCategory = prvalue
14834+
# 1986| getRValue(): [ClassAggregateLiteral] {...}
14835+
# 1986| Type = [Struct] ValCat
14836+
# 1986| ValueCategory = prvalue
14837+
# 1986| getLValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
14838+
# 1986| Type = [Struct] ValCat
14839+
# 1986| ValueCategory = lvalue
14840+
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
14841+
#-----| Type = [Struct] ValCat
14842+
#-----| ValueCategory = prvalue(load)
14843+
# 1987| getStmt(6): [ExprStmt] ExprStmt
14844+
# 1987| getExpr(): [AssignExpr] ... = ...
14845+
# 1987| Type = [Struct] ValCat
14846+
# 1987| ValueCategory = lvalue
14847+
# 1987| getLValue(): [FunctionCall] call to prvalue
14848+
# 1987| Type = [Struct] ValCat
14849+
# 1987| ValueCategory = prvalue
14850+
# 1987| getRValue(): [ClassAggregateLiteral] {...}
14851+
# 1987| Type = [Struct] ValCat
14852+
# 1987| ValueCategory = prvalue
14853+
# 1987| getLValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
14854+
# 1987| Type = [Struct] ValCat
14855+
# 1987| ValueCategory = lvalue
14856+
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
14857+
#-----| Type = [Struct] ValCat
14858+
#-----| ValueCategory = prvalue(load)
14859+
# 1988| getStmt(7): [ReturnStmt] return ...
14860+
# 1990| [TopLevelFunction] void SetStaticFuncPtr()
14861+
# 1990| <params>:
14862+
# 1990| getEntryPoint(): [BlockStmt] { ... }
14863+
# 1991| getStmt(0): [DeclStmt] declaration
14864+
# 1991| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
14865+
# 1991| Type = [Class] C
14866+
# 1991| getVariable().getInitializer(): [Initializer] initializer for c
14867+
# 1991| getExpr(): [ConstructorCall] call to C
14868+
# 1991| Type = [VoidType] void
14869+
# 1991| ValueCategory = prvalue
14870+
# 1992| getStmt(1): [DeclStmt] declaration
14871+
# 1992| getDeclarationEntry(0): [VariableDeclarationEntry] definition of pfn
14872+
# 1992| Type = [FunctionPointerType] ..(*)(..)
14873+
# 1992| getVariable().getInitializer(): [Initializer] initializer for pfn
14874+
# 1992| getExpr(): [FunctionAccess] StaticMemberFunction
14875+
# 1992| Type = [FunctionPointerType] ..(*)(..)
14876+
# 1992| ValueCategory = prvalue(load)
14877+
# 1993| getStmt(2): [ExprStmt] ExprStmt
14878+
# 1993| getExpr(): [AssignExpr] ... = ...
14879+
# 1993| Type = [FunctionPointerType] ..(*)(..)
14880+
# 1993| ValueCategory = lvalue
14881+
# 1993| getLValue(): [VariableAccess] pfn
14882+
# 1993| Type = [FunctionPointerType] ..(*)(..)
14883+
# 1993| ValueCategory = lvalue
14884+
# 1993| getRValue(): [FunctionAccess] StaticMemberFunction
14885+
# 1993| Type = [FunctionPointerType] ..(*)(..)
14886+
# 1993| ValueCategory = prvalue
14887+
# 1993| getQualifier(): [VariableAccess] c
14888+
# 1993| Type = [Class] C
14889+
# 1993| ValueCategory = lvalue
14890+
# 1994| getStmt(3): [ReturnStmt] return ...
1473414891
perf-regression.cpp:
1473514892
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
1473614893
# 4| <params>:

cpp/ql/test/library-tests/ir/ir/ir.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,4 +1970,27 @@ void test_volatile() {
19701970
x;
19711971
}
19721972

1973+
struct ValCat {
1974+
static ValCat& lvalue();
1975+
static ValCat&& xvalue();
1976+
static ValCat prvalue();
1977+
};
1978+
1979+
void value_category_test() {
1980+
ValCat c;
1981+
1982+
c.lvalue() = {};
1983+
c.xvalue() = {};
1984+
c.prvalue() = {};
1985+
ValCat::lvalue() = {};
1986+
ValCat::xvalue() = {};
1987+
ValCat::prvalue() = {};
1988+
}
1989+
1990+
void SetStaticFuncPtr() {
1991+
C c;
1992+
int (*pfn)(int) = C::StaticMemberFunction;
1993+
pfn = c.StaticMemberFunction;
1994+
}
1995+
19731996
// semmle-extractor-options: -std=c++17 --clang

0 commit comments

Comments
 (0)