Repository navigation
Unified: Support shorthand returns #22854
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
base: main
Are you sure you want to change the base?
Changes from all commits
6f6b71e
62992eb
8cdfbab
65001f0
1f4c932
b0852cc
1693f4a
cc62a1c
f447c31
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 |
|---|---|---|
|
|
@@ -91,6 +91,9 @@ newtype TDataFlowNode = | |
| TLocalVariableRefNode(AstNode repr, LocalVariable var, VariableRefKind kind) { | ||
| performsVariableAccess(repr, var, kind, _) | ||
| } or | ||
| TReturnNode(DataFlowCallable callable) { | ||
|
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. Use
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. Do you mind if we keep it as |
||
| not exists(callable.asSummarizedCallable()) // represented by TSummaryNode | ||
| } or | ||
| TCallableNode(DataFlowCallable callable) or | ||
| TImplicitParameterNode(DataFlowCallable callable, ImplicitParameterPosition pos) { | ||
| not exists(callable.asSummarizedCallable()) // represented by TSummaryNode | ||
|
|
@@ -104,7 +107,7 @@ newtype TDataFlowNode = | |
|
|
||
| class TDataFlowNodeStage1 = | ||
| TValueNode or TStrictlyIncomingValue or TExprPostUpdateNode or TLocalVariableRefNode or | ||
| TCallableNode or TImplicitParameterNode or TImplicitArgumentNode; | ||
| TReturnNode or TCallableNode or TImplicitParameterNode or TImplicitArgumentNode; | ||
|
|
||
| class TDataFlowNodeStage2 = TDataFlowNodeStage1 or TLocalSsaNode; | ||
|
|
||
|
|
@@ -152,6 +155,16 @@ class BuilderNode extends TDataFlowNodeStage1 { | |
| /** Holds if this represents the updated state of the value returned by `expr` after it has been mutated by the surrounding assignment or call. */ | ||
| predicate isPostUpdate(Expr expr) { this = TExprPostUpdateNode(expr) } | ||
|
|
||
| /** Holds if this node is the canonical representative for the return value of `callable`. */ | ||
| predicate isReturnNode(Callable callable) { this.isReturnNodeEx(toDataFlowCallable(callable)) } | ||
|
|
||
| /** | ||
| * Holds if this node is the canonical representative for the return value of `callable`. | ||
| * | ||
| * Note that this does not hold for the return node in a summarized callable. | ||
| */ | ||
| predicate isReturnNodeEx(DataFlowCallable callable) { this = TReturnNode(callable) } | ||
|
|
||
| /** Holds if this node represents an implicit parameter of `callable`. */ | ||
| predicate isImplicitParameter(DataFlowCallable callable, ImplicitParameterPosition pos) { | ||
| this = TImplicitParameterNode(callable, pos) | ||
|
|
@@ -258,6 +271,11 @@ class BuilderNode extends TDataFlowNodeStage1 { | |
| result = "[callable] " + callable.toString() | ||
| ) | ||
| or | ||
| exists(DataFlowCallable callable | | ||
| this.isReturnNodeEx(callable) and | ||
| result = "[return] " + callable.toString() | ||
| ) | ||
| or | ||
| exists(DataFlowCall call, ArgumentPosition pos | | ||
| this.isImplicitArgument(call, pos, false) and | ||
| result = "[" + pos + " arg] " + call.toString() | ||
|
|
@@ -284,6 +302,11 @@ class BuilderNode extends TDataFlowNodeStage1 { | |
| result = callable.getLocation() | ||
| ) | ||
| or | ||
| exists(DataFlowCallable callable | | ||
| this.isReturnNodeEx(callable) and | ||
| result = callable.getLocation() | ||
| ) | ||
| or | ||
| exists(DataFlowCall call | | ||
| this.isImplicitArgument(call, _, _) and | ||
| result = call.getLocation() | ||
|
|
@@ -371,6 +394,9 @@ class Node extends TDataFlowNode { | |
| /** Holds if this is the canonical representative for the given `callable`. */ | ||
| predicate isCallable(Callable callable) { this.(BuilderNode).isCallable(callable) } | ||
|
|
||
| /** Holds if this node is the canonical representative for the return value of `callable`. */ | ||
| predicate isReturnNode(Callable callable) { this.(BuilderNode).isReturnNode(callable) } | ||
|
|
||
| /** | ||
| * Gets the AST node wrapped by this data flow, if any. | ||
| */ | ||
|
|
@@ -419,8 +445,6 @@ class Node extends TDataFlowNode { | |
| result.asSourceCallable() = node.getSourceVariable().getDeclaringCallable() | ||
| ) | ||
| or | ||
| this.(BuilderNode).isImplicitParameter(result, _) | ||
| or | ||
| exists(CaptureSsaOutput::SynthesizedCaptureNode node | | ||
| this = TCaptureSsaNode(node) and | ||
| result.asSourceCallable() = node.getEnclosingCallable() | ||
|
|
@@ -433,6 +457,8 @@ class Node extends TDataFlowNode { | |
| result = call.getEnclosingCallable() | ||
| ) | ||
| or | ||
| this.(BuilderNode).isReturnNodeEx(result) | ||
| or | ||
| exists(DataFlowCallable callable | | ||
| this.isCallableEx(callable) and | ||
| result.asSourceCallable() = callable.asSourceCallable().getEnclosingCallable() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| func source(_ s: String) -> String { return s } | ||
|
|
||
| @discardableResult | ||
| func sink(_ s: Any) -> String { return "" } | ||
|
|
||
| func t1() { | ||
| func getValue() -> String { source("t1.1") } | ||
| sink(getValue()) // $ hasValueFlow=t1.1 | ||
| } |
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 think we can accept this. It's a best-effort check and spurious tuples should be harmless in practice.