mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
QL4QL: Add query suggestion use of inline test expectations
This commit is contained in:
67
ql/ql/src/codeql_ql/ast/Yaml.qll
Normal file
67
ql/ql/src/codeql_ql/ast/Yaml.qll
Normal file
@@ -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(_)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
15
ql/ql/src/queries/style/QlRefInlineExpectations.ql
Normal file
15
ql/ql/src/queries/style/QlRefInlineExpectations.ql
Normal file
@@ -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."
|
||||||
@@ -3,33 +3,6 @@
|
|||||||
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
|
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import ql as QL
|
|
||||||
private import codeql.util.test.InlineExpectationsTest
|
private import codeql.util.test.InlineExpectationsTest
|
||||||
|
private import internal.InlineExpectationsTestImpl
|
||||||
private 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
import Make<Impl>
|
import Make<Impl>
|
||||||
|
|||||||
21
ql/ql/src/utils/test/InlineExpectationsTestQuery.ql
Normal file
21
ql/ql/src/utils/test/InlineExpectationsTestQuery.ql
Normal file
@@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
ql/ql/src/utils/test/internal/InlineExpectationsTestImpl.qll
Normal file
28
ql/ql/src/utils/test/internal/InlineExpectationsTestImpl.qll
Normal file
@@ -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;
|
||||||
|
}
|
||||||
1
ql/ql/test/queries/style/QlRefInlineExpectations/Foo.qll
Normal file
1
ql/ql/test/queries/style/QlRefInlineExpectations/Foo.qll
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import ql
|
||||||
@@ -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. |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
queries/style/QlRefInlineExpectations.ql
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
query: queries/style/OmittableExists.ql
|
||||||
|
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
query: queries/style/OmittableExists.ql
|
||||||
|
postprocess:
|
||||||
|
- utils/test/InlineExpectationsTestQuery.ql
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
query: queries/style/OmittableExists.ql
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
type NUL && "%CODEQL_DIST%\codeql" database index-files ^
|
type NUL && "%CODEQL_DIST%\codeql" database index-files ^
|
||||||
--include=**/qlpack.yml ^
|
--include=**/qlpack.yml ^
|
||||||
|
--include-extension=.qlref ^
|
||||||
--size-limit=5m ^
|
--size-limit=5m ^
|
||||||
--language yaml ^
|
--language yaml ^
|
||||||
-- ^
|
-- ^
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ set -eu
|
|||||||
|
|
||||||
"$CODEQL_DIST/codeql" database index-files \
|
"$CODEQL_DIST/codeql" database index-files \
|
||||||
"--include=**/qlpack.yml" \
|
"--include=**/qlpack.yml" \
|
||||||
|
--include-extension=.qlref \
|
||||||
--size-limit=5m \
|
--size-limit=5m \
|
||||||
--language yaml \
|
--language yaml \
|
||||||
-- \
|
-- \
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ IF %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
|
|||||||
type NUL && "%CODEQL_DIST%\codeql.exe" database index-files ^
|
type NUL && "%CODEQL_DIST%\codeql.exe" database index-files ^
|
||||||
--prune=**/*.testproj ^
|
--prune=**/*.testproj ^
|
||||||
--include-extension=.yml ^
|
--include-extension=.yml ^
|
||||||
|
--include-extension=.qlref ^
|
||||||
--size-limit=5m ^
|
--size-limit=5m ^
|
||||||
--language=yaml ^
|
--language=yaml ^
|
||||||
--working-dir=. ^
|
--working-dir=. ^
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ set -eu
|
|||||||
exec "${CODEQL_DIST}/codeql" database index-files \
|
exec "${CODEQL_DIST}/codeql" database index-files \
|
||||||
--prune="**/*.testproj" \
|
--prune="**/*.testproj" \
|
||||||
--include-extension=.yml \
|
--include-extension=.yml \
|
||||||
|
--include-extension=.qlref \
|
||||||
--size-limit=5m \
|
--size-limit=5m \
|
||||||
--language=yaml \
|
--language=yaml \
|
||||||
--working-dir=.\
|
--working-dir=.\
|
||||||
|
|||||||
Reference in New Issue
Block a user