-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
QL4QL: Add query suggesting use of inline test expectations #18767
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** | ||
* Provides classes for working with YAML data. | ||
* | ||
* YAML documents are represented as abstract syntax trees whose nodes | ||
* are either YAML values or alias nodes referring to another YAML value. | ||
*/ | ||
|
||
private import codeql.yaml.Yaml as LibYaml | ||
|
||
private module YamlSig implements LibYaml::InputSig { | ||
import codeql.Locations | ||
|
||
class LocatableBase extends @yaml_locatable { | ||
Location getLocation() { yaml_locations(this, result) } | ||
|
||
string toString() { none() } | ||
} | ||
|
||
class NodeBase extends LocatableBase, @yaml_node { | ||
NodeBase getChildNode(int i) { yaml(result, _, this, i, _, _) } | ||
|
||
string getTag() { yaml(this, _, _, _, result, _) } | ||
|
||
string getAnchor() { yaml_anchors(this, result) } | ||
|
||
override string toString() { yaml(this, _, _, _, _, result) } | ||
} | ||
|
||
class ScalarNodeBase extends NodeBase, @yaml_scalar_node { | ||
int getStyle() { yaml_scalars(this, result, _) } | ||
|
||
string getValue() { yaml_scalars(this, _, result) } | ||
} | ||
|
||
class CollectionNodeBase extends NodeBase, @yaml_collection_node { } | ||
|
||
class MappingNodeBase extends CollectionNodeBase, @yaml_mapping_node { } | ||
|
||
class SequenceNodeBase extends CollectionNodeBase, @yaml_sequence_node { } | ||
|
||
class AliasNodeBase extends NodeBase, @yaml_alias_node { | ||
string getTarget() { yaml_aliases(this, result) } | ||
} | ||
|
||
class ParseErrorBase extends LocatableBase, @yaml_error { | ||
string getMessage() { yaml_errors(this, result) } | ||
} | ||
} | ||
|
||
import LibYaml::Make<YamlSig> | ||
|
||
/** A `.qlref` YAML document. */ | ||
class QlRefDocument extends YamlDocument { | ||
QlRefDocument() { this.getFile().getExtension() = "qlref" } | ||
|
||
/** Holds if this `.qlref` file uses inline test expectations. */ | ||
predicate usesInlineExpectations() { | ||
exists(YamlMapping n, YamlScalar value | | ||
n.getDocument() = this and | ||
value.getValue().matches("%InlineExpectations%") | ||
| | ||
value = n.lookup("postprocess") | ||
or | ||
value = n.lookup("postprocess").(YamlSequence).getElement(_) | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** | ||
* @name Query test without inline test expectations | ||
* @description Using inline test expectations is a best practice for writing query tests. | ||
* @kind problem | ||
* @problem.severity warning | ||
* @id ql/qlref-inline-expectations | ||
* @precision high | ||
*/ | ||
|
||
import ql | ||
import codeql_ql.ast.Yaml | ||
|
||
from QlRefDocument f | ||
where not f.usesInlineExpectations() | ||
select f, "Query test does not use inline test expectations." |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* @kind test-postprocess | ||
*/ | ||
|
||
private import ql | ||
private import codeql.util.test.InlineExpectationsTest as T | ||
private import internal.InlineExpectationsTestImpl | ||
import T::TestPostProcessing | ||
import T::TestPostProcessing::Make<Impl, Input> | ||
|
||
private module Input implements T::TestPostProcessing::InputSig<Impl> { | ||
string getRelativeUrl(Location location) { | ||
exists(File f, int startline, int startcolumn, int endline, int endcolumn | | ||
location.hasLocationInfo(_, startline, startcolumn, endline, endcolumn) and | ||
f = location.getFile() | ||
| | ||
result = | ||
f.getRelativePath() + ":" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
private import ql as QL | ||
private import codeql.util.test.InlineExpectationsTest | ||
|
||
module Impl implements InlineExpectationsTestSig { | ||
private import codeql_ql.ast.internal.TreeSitter as TS | ||
|
||
private newtype TExpectationComment = MkExpectationComment(TS::QL::LineComment comment) | ||
|
||
/** | ||
* Represents a line comment. | ||
*/ | ||
class ExpectationComment extends TExpectationComment { | ||
TS::QL::LineComment comment; | ||
|
||
ExpectationComment() { this = MkExpectationComment(comment) } | ||
|
||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */ | ||
string getContents() { result = comment.getValue().suffix(2) } | ||
|
||
/** Gets a textual representation of this element. */ | ||
string toString() { result = comment.toString() } | ||
|
||
/** Gets the location of this comment. */ | ||
Location getLocation() { result = comment.getLocation() } | ||
} | ||
|
||
class Location = QL::Location; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import ql |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
| QlRefInlineExpectations.qlref:1:1:1:40 | queries ... ions.ql | Query test does not use inline test expectations. | | ||
| Test3.qlref:1:1:1:39 | query: ... ists.ql | Query test does not use inline test expectations. | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
queries/style/QlRefInlineExpectations.ql | ||
Check warning Code scanning / CodeQL Query test without inline test expectations Warning test
Query test does not use inline test expectations.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
query: queries/style/OmittableExists.ql | ||
postprocess: utils/test/InlineExpectationsTestQuery.ql |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
query: queries/style/OmittableExists.ql | ||
postprocess: | ||
- utils/test/InlineExpectationsTestQuery.ql |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
query: queries/style/OmittableExists.ql | ||
Check warning Code scanning / CodeQL Query test without inline test expectations Warning test
Query test does not use inline test expectations.
|
Check warning
Code scanning / CodeQL
Class QLDoc style. Warning test