Skip to content
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

Python: Move min/maxParameter methods to Function class #18871

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
category: minorAnalysis
---

- Added the methods `getMinArguments` and `getMaxArguments` to the `Function` class. These return the minimum and maximum positional arguments that the given function accepts.
12 changes: 12 additions & 0 deletions python/ql/lib/semmle/python/Function.qll
Original file line number Diff line number Diff line change
@@ -163,6 +163,18 @@ class Function extends Function_, Scope, AstNode {
ret.getValue() = result.getNode()
)
}

/** Gets the minimum number of positional arguments that can be correctly passed to this function. */
int getMinArguments() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming: Should these be getMinPositionalArguments, something like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a mouthful (and it suggests the existence of getMinKeywordArguments, which I'm not entirely sure makes sense), but it's probably a good idea to proactively disambiguate things here. At the very least, renaming it to something shorter will be easy to do if we feel like it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 11e6194.

result = count(this.getAnArg()) - count(this.getDefinition().getArgs().getADefault())
}

/** Gets the maximum number of positional arguments that can be correctly passed to this function. */
int getMaxArguments() {
if exists(this.getVararg())
then result = 2147483647 // INT_MAX
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh this is an interesting trap. I suggest at least putting it in the QLDoc, i.e. if the function doesn't take varargs, the result is INT_MAX.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you've got a superfluous negation there (if the function does take varargs, the result is INT_MAX), but I agree this should be documented better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 11e6194.

else result = count(this.getAnArg())
}
}

/** A def statement. Note that FunctionDef extends Assign as a function definition binds the newly created function */
16 changes: 2 additions & 14 deletions python/ql/lib/semmle/python/objects/ObjectAPI.qll
Original file line number Diff line number Diff line change
@@ -738,21 +738,9 @@ class PythonFunctionValue extends FunctionValue {
else result = "function " + this.getQualifiedName()
}

override int minParameters() {
exists(Function f |
f = this.getScope() and
result = count(f.getAnArg()) - count(f.getDefinition().getArgs().getADefault())
)
}
override int minParameters() { result = this.getScope().getMinArguments() }

override int maxParameters() {
exists(Function f |
f = this.getScope() and
if exists(f.getVararg())
then result = 2147483647 // INT_MAX
else result = count(f.getAnArg())
)
}
override int maxParameters() { result = this.getScope().getMaxArguments() }

/** Gets a control flow node corresponding to a return statement in this function */
ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() }