Merge pull request #9825 from erik-krogh/repeatedWord

QL: add ql/repeated-word query
This commit is contained in:
Erik Krogh Kristensen
2022-08-10 07:25:26 +02:00
committed by GitHub
17 changed files with 62 additions and 18 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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` */

View File

@@ -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.
*/

View File

@@ -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)

View File

@@ -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"))
}

View File

@@ -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

View File

@@ -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)

View 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 + "."

View File

@@ -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

View File

@@ -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. */

View File

@@ -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)`