mirror of
https://github.com/github/codeql.git
synced 2026-04-21 06:55:31 +02:00
QL: add pretty AST for YAML and a QLPack utility class
This commit is contained in:
@@ -2019,3 +2019,187 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
|
||||
pred = directMember("getQualifier") and result = this.getQualifier()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Classes modelling YAML AST nodes.
|
||||
*/
|
||||
module YAML {
|
||||
/** A node in a YAML file */
|
||||
class YAMLNode extends TYAMLNode, AstNode {
|
||||
/** Holds if the predicate is a root node (has no parent) */
|
||||
predicate isRoot() { not exists(getParent()) }
|
||||
}
|
||||
|
||||
/** A YAML comment. */
|
||||
class YAMLComment extends TYamlCommemt, YAMLNode {
|
||||
Generated::YamlComment yamlcomment;
|
||||
|
||||
YAMLComment() { this = TYamlCommemt(yamlcomment) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "YAMLComment" }
|
||||
}
|
||||
|
||||
/** A YAML entry. */
|
||||
class YAMLEntry extends TYamlEntry, YAMLNode {
|
||||
Generated::YamlEntry yamle;
|
||||
|
||||
YAMLEntry() { this = TYamlEntry(yamle) }
|
||||
|
||||
/** Gets the key of this YAML entry. */
|
||||
YAMLKey getKey() {
|
||||
exists(Generated::YamlKeyvaluepair pair |
|
||||
pair.getParent() = yamle and
|
||||
result = TYamlKey(pair.getKey())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the value of this YAML entry. */
|
||||
YAMLValue getValue() {
|
||||
exists(Generated::YamlKeyvaluepair pair |
|
||||
pair.getParent() = yamle and
|
||||
result = TYamlValue(pair.getValue())
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "YAMLEntry" }
|
||||
}
|
||||
|
||||
/** A YAML key. */
|
||||
class YAMLKey extends TYamlKey, YAMLNode {
|
||||
Generated::YamlKey yamlkey;
|
||||
|
||||
YAMLKey() { this = TYamlKey(yamlkey) }
|
||||
|
||||
/**
|
||||
* Gets the value of this YAML key.
|
||||
*/
|
||||
YAMLValue getValue() {
|
||||
exists(Generated::YamlKeyvaluepair pair |
|
||||
pair.getKey() = yamlkey and result = TYamlValue(pair.getValue())
|
||||
)
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "YAMLKey" }
|
||||
|
||||
/** Gets the value of this YAML value. */
|
||||
string getNamePart(int i) {
|
||||
i = 0 and result = yamlkey.getChild(0).(Generated::SimpleId).getValue()
|
||||
or
|
||||
exists(YAMLKey child |
|
||||
child = TYamlKey(yamlkey.getChild(1)) and
|
||||
result = child.getNamePart(i - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the name parts of this YAML key concatenated with `/`.
|
||||
* Dashes are replaced with `/` (because we don't have that information in the generated AST).
|
||||
*/
|
||||
string getQualifiedName() {
|
||||
result = concat(string part, int i | part = getNamePart(i) | part, "/" order by i)
|
||||
}
|
||||
}
|
||||
|
||||
/** A YAML list item. */
|
||||
class YAMLListItem extends TYamlListitem, YAMLNode {
|
||||
Generated::YamlListitem yamllistitem;
|
||||
|
||||
YAMLListItem() { this = TYamlListitem(yamllistitem) }
|
||||
|
||||
/**
|
||||
* Gets the value of this YAML list item.
|
||||
*/
|
||||
YAMLValue getValue() { result = TYamlValue(yamllistitem.getChild()) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "YAMLListItem" }
|
||||
}
|
||||
|
||||
/** A YAML value. */
|
||||
class YAMLValue extends TYamlValue, YAMLNode {
|
||||
Generated::YamlValue yamlvalue;
|
||||
|
||||
YAMLValue() { this = TYamlValue(yamlvalue) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "YAMLValue" }
|
||||
|
||||
/** Gets the value of this YAML value. */
|
||||
string getValue() { result = yamlvalue.getValue() }
|
||||
}
|
||||
|
||||
// to not expose the entire `File` API on `QlPack`.
|
||||
private newtype TQLPack = MKQlPack(File file) { file.getBaseName() = "qlpack.yml" }
|
||||
|
||||
YAMLEntry test() { not result.isRoot() }
|
||||
|
||||
/**
|
||||
* A `qlpack.yml` file.
|
||||
*/
|
||||
class QLPack extends MKQlPack {
|
||||
File file;
|
||||
|
||||
QLPack() { this = MKQlPack(file) }
|
||||
|
||||
private string getProperty(string name) {
|
||||
exists(YAMLEntry entry |
|
||||
entry.isRoot() and
|
||||
entry.getKey().getQualifiedName() = name and
|
||||
result = entry.getValue().getValue() and
|
||||
entry.getLocation().getFile() = file
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the name of this qlpack */
|
||||
string getName() { result = getProperty("name") }
|
||||
|
||||
/** Gets the version of this qlpack */
|
||||
string getVersion() { result = getProperty("version") }
|
||||
|
||||
/** Gets the database scheme of this qlpack */
|
||||
string getDbScheme() { result = getProperty("dbscheme") }
|
||||
|
||||
/** Gets the extractor of this qlpack */
|
||||
string getExtractor() { result = getProperty("extractor") }
|
||||
|
||||
string toString() { result = getName() }
|
||||
|
||||
/** Gets the file that this `QLPack` represents. */
|
||||
File getFile() { result = file }
|
||||
|
||||
private predicate isADependency(YAMLEntry entry) {
|
||||
exists(YAMLEntry deps |
|
||||
deps.getLocation().getFile() = file and entry.getLocation().getFile() = file
|
||||
|
|
||||
deps.isRoot() and
|
||||
deps.getKey().getQualifiedName() = "dependencies" and
|
||||
entry.getLocation().getStartLine() = 1 + deps.getLocation().getStartLine() and
|
||||
entry.getLocation().getStartColumn() > deps.getLocation().getStartColumn()
|
||||
)
|
||||
or
|
||||
exists(YAMLEntry prev | isADependency(prev) |
|
||||
prev.getLocation().getFile() = file and
|
||||
entry.getLocation().getFile() = file and
|
||||
entry.getLocation().getStartLine() = 1 + prev.getLocation().getStartLine() and
|
||||
entry.getLocation().getStartColumn() = prev.getLocation().getStartColumn()
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasDependency(string name, string version) {
|
||||
exists(YAMLEntry entry | isADependency(entry) |
|
||||
entry.getKey().getQualifiedName() = name and
|
||||
entry.getValue().getValue() = version
|
||||
)
|
||||
}
|
||||
|
||||
Location getLocation() {
|
||||
// hacky, just pick the first node in the file.
|
||||
result =
|
||||
min(YAMLNode entry, Location l, File f |
|
||||
entry.getLocation().getFile() = file and
|
||||
f = file and
|
||||
l = entry.getLocation()
|
||||
|
|
||||
entry order by l.getStartLine(), l.getStartColumn(), l.getEndColumn(), l.getEndLine()
|
||||
).getLocation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,12 @@ newtype TAstNode =
|
||||
TUnaryExpr(Generated::UnaryExpr unaryexpr) or
|
||||
TDontCare(Generated::Underscore dontcare) or
|
||||
TModuleExpr(Generated::ModuleExpr me) or
|
||||
TPredicateExpr(Generated::PredicateExpr pe)
|
||||
TPredicateExpr(Generated::PredicateExpr pe) or
|
||||
TYamlCommemt(Generated::YamlComment yc) or
|
||||
TYamlEntry(Generated::YamlEntry ye) or
|
||||
TYamlKey(Generated::YamlKey yk) or
|
||||
TYamlListitem(Generated::YamlListitem yli) or
|
||||
TYamlValue(Generated::YamlValue yv)
|
||||
|
||||
class TFormula =
|
||||
TDisjunction or TConjunction or TComparisonFormula or TQuantifier or TNegation or TIfFormula or
|
||||
@@ -75,6 +80,9 @@ class TCall = TPredicateCall or TMemberCall or TNoneCall or TAnyCall;
|
||||
|
||||
class TModuleRef = TImport or TModuleExpr;
|
||||
|
||||
class TYAMLNode = TYamlCommemt or TYamlEntry or TYamlKey or TYamlListitem or
|
||||
TYamlValue;
|
||||
|
||||
private Generated::AstNode toGeneratedFormula(AST::AstNode n) {
|
||||
n = TConjunction(result) or
|
||||
n = TDisjunction(result) or
|
||||
@@ -105,6 +113,14 @@ private Generated::AstNode toGeneratedExpr(AST::AstNode n) {
|
||||
n = TDontCare(result)
|
||||
}
|
||||
|
||||
private Generated::AstNode toGenerateYAML(AST::AstNode n) {
|
||||
n = TYamlCommemt(result) or
|
||||
n = TYamlEntry(result) or
|
||||
n = TYamlKey(result) or
|
||||
n = TYamlListitem(result) or
|
||||
n = TYamlValue(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying TreeSitter entity for a given AST node.
|
||||
*/
|
||||
@@ -113,6 +129,8 @@ Generated::AstNode toGenerated(AST::AstNode n) {
|
||||
or
|
||||
result = toGeneratedFormula(n)
|
||||
or
|
||||
result = toGenerateYAML(n)
|
||||
or
|
||||
result.(Generated::ParExpr).getChild() = toGenerated(n)
|
||||
or
|
||||
result =
|
||||
|
||||
Reference in New Issue
Block a user