mirror of
https://github.com/github/codeql.git
synced 2026-03-28 10:18:17 +01:00
Merge pull request #9825 from erik-krogh/repeatedWord
QL: add ql/repeated-word query
This commit is contained in:
@@ -699,7 +699,7 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
|
||||
call.getTarget() = f and
|
||||
// AST dataflow treats a reference as if it were the referred-to object, while the dataflow
|
||||
// models treat references as pointers. If the return type of the call is a reference, then
|
||||
// look for data flow the the referred-to object, rather than the reference itself.
|
||||
// look for data flow to the referred-to object, rather than the reference itself.
|
||||
if call.getType().getUnspecifiedType() instanceof ReferenceType
|
||||
then outModel.isReturnValueDeref()
|
||||
else outModel.isReturnValue()
|
||||
|
||||
@@ -1573,7 +1573,7 @@ private module SimpleRangeAnalysisCached {
|
||||
result = min([max(getTruncatedUpperBounds(expr)), getGuardedUpperBound(expr)])
|
||||
}
|
||||
|
||||
/** Holds if the upper bound of `expr` may have been widened. This means the the upper bound is in practice likely to be overly wide. */
|
||||
/** Holds if the upper bound of `expr` may have been widened. This means the upper bound is in practice likely to be overly wide. */
|
||||
cached
|
||||
predicate upperBoundMayBeWidened(Expr e) {
|
||||
isRecursiveExpr(e) and
|
||||
|
||||
@@ -335,7 +335,7 @@ module Expressions {
|
||||
// ```csharp
|
||||
// new Dictionary<int, string>() { [0] = "Zero", [1] = "One", [2] = "Two" }
|
||||
// ```
|
||||
// need special treatment, because the the accesses `[0]`, `[1]`, and `[2]`
|
||||
// need special treatment, because the accesses `[0]`, `[1]`, and `[2]`
|
||||
// have no qualifier.
|
||||
this = any(MemberInitializer mi).getLValue()
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class ExternalApi extends DotNet::Callable {
|
||||
defaultAdditionalTaintStep(this.getAnInput(), _)
|
||||
}
|
||||
|
||||
/** Holds if this API is is a constructor without parameters. */
|
||||
/** Holds if this API is a constructor without parameters. */
|
||||
private predicate isParameterlessConstructor() {
|
||||
this instanceof Constructor and this.getNumberOfParameters() = 0
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import go
|
||||
|
||||
/** Gets the global value number of of `e`, which is the `i`th case label of `switch`. */
|
||||
/** Gets the global value number of `e`, which is the `i`th case label of `switch`. */
|
||||
GVN switchCaseGVN(SwitchStmt switch, int i, Expr e) {
|
||||
e = switch.getCase(i).getExpr(0) and result = e.getGlobalValueNumber()
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class ExternalApi extends Callable {
|
||||
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
|
||||
}
|
||||
|
||||
/** Holds if this API is is a constructor without parameters. */
|
||||
/** Holds if this API is a constructor without parameters. */
|
||||
private predicate isParameterlessConstructor() {
|
||||
this instanceof Constructor and this.getNumberOfParameters() = 0
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Helper file that imports all framework modeling.
|
||||
*/
|
||||
|
||||
// If you add modeling of a new framework/library, remember to add it it to the docs in
|
||||
// If you add modeling of a new framework/library, remember to add it to the docs in
|
||||
// `docs/codeql/support/reusables/frameworks.rst`
|
||||
private import semmle.python.frameworks.Aioch
|
||||
private import semmle.python.frameworks.Aiohttp
|
||||
|
||||
@@ -333,7 +333,7 @@ abstract class Sanitizer extends string {
|
||||
/** Holds if `taint` cannot flow through `node`. */
|
||||
predicate sanitizingNode(TaintKind taint, ControlFlowNode node) { none() }
|
||||
|
||||
/** Holds if `call` removes removes the `taint` */
|
||||
/** Holds if `call` removes the `taint` */
|
||||
predicate sanitizingCall(TaintKind taint, FunctionObject callee) { none() }
|
||||
|
||||
/** Holds if `test` shows value to be untainted with `taint` */
|
||||
|
||||
@@ -156,28 +156,42 @@ class TopLevel extends TTopLevel, AstNode {
|
||||
override QLDoc getQLDoc() { result = this.getMember(0) }
|
||||
}
|
||||
|
||||
class QLDoc extends TQLDoc, AstNode {
|
||||
abstract class Comment extends AstNode, TComment {
|
||||
abstract string getContents();
|
||||
}
|
||||
|
||||
class QLDoc extends TQLDoc, Comment {
|
||||
QL::Qldoc qldoc;
|
||||
|
||||
QLDoc() { this = TQLDoc(qldoc) }
|
||||
|
||||
string getContents() { result = qldoc.getValue() }
|
||||
override string getContents() { result = qldoc.getValue() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "QLDoc" }
|
||||
|
||||
override AstNode getParent() { result.getQLDoc() = this }
|
||||
}
|
||||
|
||||
class BlockComment extends TBlockComment, AstNode {
|
||||
class BlockComment extends TBlockComment, Comment {
|
||||
QL::BlockComment comment;
|
||||
|
||||
BlockComment() { this = TBlockComment(comment) }
|
||||
|
||||
string getContents() { result = comment.getValue() }
|
||||
override string getContents() { result = comment.getValue() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BlockComment" }
|
||||
}
|
||||
|
||||
class LineComment extends TLineComment, Comment {
|
||||
QL::LineComment comment;
|
||||
|
||||
LineComment() { this = TLineComment(comment) }
|
||||
|
||||
override string getContents() { result = comment.getValue() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "LineComment" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `from, where, select` part of a QL query.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ newtype TAstNode =
|
||||
TTopLevel(QL::Ql file) or
|
||||
TQLDoc(QL::Qldoc qldoc) or
|
||||
TBlockComment(QL::BlockComment comment) or
|
||||
TLineComment(QL::LineComment comment) or
|
||||
TClasslessPredicate(QL::ClasslessPredicate pred) or
|
||||
TVarDecl(QL::VarDecl decl) or
|
||||
TFieldDecl(QL::Field field) or
|
||||
@@ -89,6 +90,8 @@ class TYamlNode = TYamlCommemt or TYamlEntry or TYamlKey or TYamlListitem or TYa
|
||||
|
||||
class TSignatureExpr = TPredicateExpr or TType;
|
||||
|
||||
class TComment = TQLDoc or TBlockComment or TLineComment;
|
||||
|
||||
/** DEPRECATED: Alias for TYamlNode */
|
||||
deprecated class TYAMLNode = TYamlNode;
|
||||
|
||||
@@ -154,6 +157,8 @@ QL::AstNode toQL(AST::AstNode n) {
|
||||
or
|
||||
n = TBlockComment(result)
|
||||
or
|
||||
n = TLineComment(result)
|
||||
or
|
||||
n = TClasslessPredicate(result)
|
||||
or
|
||||
n = TVarDecl(result)
|
||||
|
||||
@@ -78,7 +78,7 @@ private class Folder_ extends ContainerOrModule, TFolder {
|
||||
|
||||
override ContainerOrModule getEnclosing() {
|
||||
result = TFolder(f.getParentContainer()) and
|
||||
// if this the the root, then we stop.
|
||||
// if this the root, then we stop.
|
||||
not exists(f.getFile("qlpack.yml"))
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ private AstNode classUnion() {
|
||||
|
||||
private AstNode benign() {
|
||||
not result.getLocation().getFile().getExtension() = ["ql", "qll"] or // ignore dbscheme files
|
||||
result instanceof BlockComment or
|
||||
result instanceof Comment or
|
||||
not exists(result.toString()) or // <- invalid code
|
||||
// cached-stages pattern
|
||||
result.(Module).getAMember().(ClasslessPredicate).getName() = "forceStage" or
|
||||
|
||||
@@ -57,7 +57,7 @@ class CandidatePredicate extends Predicate {
|
||||
this.getName()
|
||||
.regexpCapture("(.+)" + ["0", "helper", "aux", "cand", "Helper", "Aux", "Cand"], 1)
|
||||
or
|
||||
// Or this this predicate is named "foo02" and `pred` is named "foo01".
|
||||
// Or this predicate is named "foo02" and `pred` is named "foo01".
|
||||
exists(int n, string name |
|
||||
hasNameWithNumberSuffix(pred, name, n) and
|
||||
hasNameWithNumberSuffix(this, name, n - 1)
|
||||
|
||||
25
ql/ql/src/queries/style/RepeatedWord.ql
Normal file
25
ql/ql/src/queries/style/RepeatedWord.ql
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @name Comment has repeated word
|
||||
* @description Comment has repeated word.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @id ql/repeated-word
|
||||
* @precision very-high
|
||||
*/
|
||||
|
||||
import ql
|
||||
|
||||
/** Gets a word used in `node` */
|
||||
string getWord(Comment node) { result = node.getContents().regexpFind("\\b[A-Za-z]+\\b", _, _) }
|
||||
|
||||
Comment hasRepeatedWord(string word) {
|
||||
word = getWord(result) and
|
||||
result.getContents().regexpMatch(".*[\\s]" + word + "\\s+" + word + "[\\s.,].*")
|
||||
}
|
||||
|
||||
from Comment comment, string word
|
||||
where
|
||||
comment = hasRepeatedWord(word) and
|
||||
// lots of these, and I can't just change old dbschemes.
|
||||
not (word = "type" and comment.getLocation().getFile().getExtension() = "dbscheme")
|
||||
select comment, "The comment repeats " + word + "."
|
||||
@@ -348,7 +348,7 @@ module ExprNodes {
|
||||
/** Gets an argument of this call. */
|
||||
final ExprCfgNode getAnArgument() { result = this.getArgument(_) }
|
||||
|
||||
/** Gets the the keyword argument whose key is `keyword` of this call. */
|
||||
/** Gets the keyword argument whose key is `keyword` of this call. */
|
||||
final ExprCfgNode getKeywordArgument(string keyword) {
|
||||
exists(PairCfgNode n |
|
||||
e.hasCfgChild(e.getAnArgument(), this, n) and
|
||||
|
||||
@@ -79,7 +79,7 @@ class CallNode extends LocalSourceNode, ExprNode {
|
||||
result.getExprNode() = node.getPositionalArgument(n)
|
||||
}
|
||||
|
||||
/** Gets the name of the the method called by the method call (if any) corresponding to this data-flow node */
|
||||
/** Gets the name of the method called by the method call (if any) corresponding to this data-flow node */
|
||||
string getMethodName() { result = node.getExpr().(MethodCall).getMethodName() }
|
||||
|
||||
/** Gets the number of arguments of this call. */
|
||||
|
||||
@@ -379,7 +379,7 @@ class GraphqlFieldResolutionMethod extends Method, HTTP::Server::RequestHandler:
|
||||
result.(KeywordParameter).hasName(argDefn.getArgumentName())
|
||||
or
|
||||
// TODO this will cause false positives because now *anything* in the **args
|
||||
// param will be flagged as as RoutedParameter/RemoteFlowSource, but really
|
||||
// param will be flagged as RoutedParameter/RemoteFlowSource, but really
|
||||
// only the hash keys corresponding to the defined arguments are user input
|
||||
// others could be things defined in the `:extras` keyword argument to the `argument`
|
||||
result instanceof HashSplatParameter // often you see `def field(**args)`
|
||||
|
||||
Reference in New Issue
Block a user