Skip to content

Commit 6b37cb0

Browse files
committed
C++: Use the same 'template expansion mechanism' for free functions that we use for member functions.
1 parent 8edf19a commit 6b37cb0

File tree

1 file changed

+41
-20
lines changed

1 file changed

+41
-20
lines changed

cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -435,12 +435,17 @@ private predicate elementSpec(
435435
}
436436

437437
/** Gets the fully templated version of `f`. */
438-
private Function getFullyTemplatedMemberFunction(Function f) {
438+
private Function getFullyTemplatedFunction(Function f) {
439439
not f.isFromUninstantiatedTemplate(_) and
440-
exists(Class c, Class templateClass, int i |
441-
c.isConstructedFrom(templateClass) and
442-
f = c.getAMember(i) and
443-
result = templateClass.getCanonicalMember(i)
440+
(
441+
exists(Class c, Class templateClass, int i |
442+
c.isConstructedFrom(templateClass) and
443+
f = c.getAMember(i) and
444+
result = templateClass.getCanonicalMember(i)
445+
)
446+
or
447+
not exists(f.getDeclaringType()) and
448+
f.isConstructedFrom(result)
444449
)
445450
}
446451

@@ -464,14 +469,14 @@ string getParameterTypeWithoutTemplateArguments(Function f, int n) {
464469
*/
465470
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
466471
exists(Function templateFunction |
467-
templateFunction = getFullyTemplatedMemberFunction(f) and
472+
templateFunction = getFullyTemplatedFunction(f) and
468473
remaining = templateFunction.getNumberOfTemplateArguments() and
469474
result = getParameterTypeWithoutTemplateArguments(templateFunction, n)
470475
)
471476
or
472477
exists(string mid, TemplateParameter tp, Function templateFunction |
473478
mid = getTypeNameWithoutFunctionTemplates(f, n, remaining + 1) and
474-
templateFunction = getFullyTemplatedMemberFunction(f) and
479+
templateFunction = getFullyTemplatedFunction(f) and
475480
tp = templateFunction.getTemplateArgument(remaining) and
476481
result = mid.replaceAll(tp.getName(), "func:" + remaining.toString())
477482
)
@@ -482,12 +487,18 @@ private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remain
482487
* with `class:N` (where `N` is the index of the template).
483488
*/
484489
private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
490+
// If there is a declaring type then we start by expanding the function templates
485491
exists(Class template |
486492
f.getDeclaringType().isConstructedFrom(template) and
487493
remaining = template.getNumberOfTemplateArguments() and
488494
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
489495
)
490496
or
497+
// If there is no declaring type we're done after expanding the function templates
498+
not exists(f.getDeclaringType()) and
499+
remaining = 0 and
500+
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
501+
or
491502
exists(string mid, TemplateParameter tp, Class template |
492503
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
493504
f.getDeclaringType().isConstructedFrom(template) and
@@ -750,17 +761,17 @@ private predicate elementSpecWithArguments0(
750761

751762
/**
752763
* Holds if `elementSpec(namespace, type, subtypes, name, signature, _)` and
753-
* `method`'s signature matches `signature`.
764+
* `func`'s signature matches `signature`.
754765
*
755766
* `signature` may contain template parameter names that are bound by `type` and `name`.
756767
*/
757768
pragma[nomagic]
758769
private predicate elementSpecMatchesSignature(
759-
Function method, string namespace, string type, boolean subtypes, string name, string signature
770+
Function func, string namespace, string type, boolean subtypes, string name, string signature
760771
) {
761772
elementSpec(namespace, pragma[only_bind_into](type), subtypes, pragma[only_bind_into](name),
762773
pragma[only_bind_into](signature), _) and
763-
signatureMatches(method, signature, type, name, 0)
774+
signatureMatches(func, signature, type, name, 0)
764775
}
765776

766777
/**
@@ -776,13 +787,22 @@ private predicate hasClassAndName(Class classWithMethod, Function method, string
776787
)
777788
}
778789

790+
bindingset[name]
791+
pragma[inline_late]
792+
private predicate funcHasQualifiedName(Function func, string namespace, string name) {
793+
exists(string nameWithoutArgs |
794+
parseAngles(name, nameWithoutArgs, _, "") and
795+
func.hasQualifiedName(namespace, name)
796+
)
797+
}
798+
779799
/**
780800
* Holds if `namedClass` is in namespace `namespace` and has
781801
* name `type` (excluding any template parameters).
782802
*/
783803
bindingset[type, namespace]
784804
pragma[inline_late]
785-
private predicate hasQualifiedName(Class namedClass, string namespace, string type) {
805+
private predicate classHasQualifiedName(Class namedClass, string namespace, string type) {
786806
exists(string typeWithoutArgs |
787807
parseAngles(type, typeWithoutArgs, _, "") and
788808
namedClass.hasQualifiedName(namespace, typeWithoutArgs)
@@ -804,15 +824,16 @@ private Element interpretElement0(
804824
string namespace, string type, boolean subtypes, string name, string signature
805825
) {
806826
(
807-
elementSpec(namespace, type, subtypes, name, signature, _) and
808827
// Non-member functions
809-
exists(Function func |
810-
func.hasQualifiedName(namespace, name) and
811-
type = "" and
812-
matchesSignature(func, signature) and
813-
subtypes = false and
814-
not exists(func.getDeclaringType()) and
815-
result = func
828+
elementSpec(namespace, type, subtypes, name, signature, _) and
829+
subtypes = false and
830+
type = "" and
831+
(
832+
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
833+
or
834+
signature = "" and
835+
elementSpec(namespace, type, subtypes, name, "", _) and
836+
funcHasQualifiedName(result, namespace, name)
816837
)
817838
or
818839
// Member functions
@@ -825,7 +846,7 @@ private Element interpretElement0(
825846
elementSpec(namespace, type, subtypes, name, "", _) and
826847
hasClassAndName(classWithMethod, result, name)
827848
) and
828-
hasQualifiedName(namedClass, namespace, type) and
849+
classHasQualifiedName(namedClass, namespace, type) and
829850
(
830851
// member declared in the named type or a subtype of it
831852
subtypes = true and

0 commit comments

Comments
 (0)