Files
codeql/python/ql/src/Expressions/DuplicateKeyInDictionaryLiteral.ql
Copilot 717ff62d70 Python: deprecate AstNode.getAFlowNode() and rewrite internal callers
Preparatory refactor for the shared-CFG dataflow migration.

Deprecates the AstNode.getAFlowNode() cached predicate on the public
Python QL API and rewrites all ~140 internal callers across lib/, src/,
test/, and tools/ from `expr.getAFlowNode() = cfgNode` to
`cfgNode.getNode() = expr`, using ControlFlowNode.getNode() which
already exists in Flow.qll.

The predicate itself is preserved (with a deprecation note pointing at
the new pattern) so external users do not experience churn — they can
migrate at their own pace and the AST/CFG hierarchies still get the
intended untangling once the deprecation eventually elapses.

Semantic noop verified by:
- All 361 lib/ + src/ queries compile clean.
- All 122 ControlFlow + PointsTo library-tests pass.
- All 64 dataflow library-tests pass.
- All 113 Variables/Exceptions/Expressions/Statements/Functions/Imports/
  Security/CWE-798/ModificationOfParameterWithDefault query-tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-22 14:55:19 +02:00

51 lines
1.3 KiB
Plaintext
Raw Blame History

/**
* @name Duplicate key in dict literal
* @description Duplicate key in dict literal. All but the last will be lost.
* @kind problem
* @tags quality
* maintainability
* useless-code
* external/cwe/cwe-561
* @problem.severity warning
* @sub-severity high
* @precision very-high
* @id py/duplicate-key-dict-literal
*/
import python
import semmle.python.strings
predicate dict_key(Dict d, Expr k, string s) {
k = d.getAKey() and
(
s = k.(Num).getN()
or
// We use <20> to mark unrepresentable characters
// so two instances of <20> may represent different strings in the source code
not "<22>" = s.charAt(_) and
exists(StringLiteral c | c = k |
s = "u\"" + c.getText() + "\"" and c.isUnicode()
or
s = "b\"" + c.getText() + "\"" and not c.isUnicode()
)
)
}
from Dict d, Expr k1, Expr k2
where
exists(string s | dict_key(d, k1, s) and dict_key(d, k2, s) and k1 != k2) and
(
exists(BasicBlock b, int i1, int i2 |
b.getNode(i1).getNode() = k1 and
b.getNode(i2).getNode() = k2 and
i1 < i2
)
or
exists(ControlFlowNode k1Cfg, ControlFlowNode k2Cfg |
k1Cfg.getNode() = k1 and k2Cfg.getNode() = k2
|
k1Cfg.getBasicBlock().strictlyDominates(k2Cfg.getBasicBlock())
)
)
select k1, "Dictionary key " + repr(k1) + " is subsequently $@.", k2, "overwritten"