From 464773d99a9a04624dd26ee6b5ecaa1bf9e08d6e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 15 Jun 2020 11:19:43 +0100 Subject: [PATCH 1/4] Add initial implementation of PrintAST for Go Known shortcomings: * Uses getAQlClass rather than tagging AST nodes with a canonical class, as the C++ version of the same query does * Types and go.mod lines are not printed informatively (typically we just get a short description of the node kind, e.g. 'function type') * Children are always named for their child indices; we should give informative names to the edges where an accessor is declared (e.g. IfStmt names its children 'init', 'cond', 'if', 'else') --- ql/src/semmle/go/PrintAst.ql | 16 +++ ql/src/semmle/go/PrintAst.qll | 195 ++++++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 ql/src/semmle/go/PrintAst.ql create mode 100644 ql/src/semmle/go/PrintAst.qll diff --git a/ql/src/semmle/go/PrintAst.ql b/ql/src/semmle/go/PrintAst.ql new file mode 100644 index 00000000000..f73b2a21ad9 --- /dev/null +++ b/ql/src/semmle/go/PrintAst.ql @@ -0,0 +1,16 @@ +/** + * @name Print AST + * @description Outputs a representation of the Abstract Syntax Tree. + * @id go/print-ast + * @kind graph + */ + +import go +import PrintAst + +/** + * Hook to customize the functions printed by this query. + */ +class Cfg extends PrintAstConfiguration { + override predicate shouldPrintFunction(FuncDef func) { any() } +} diff --git a/ql/src/semmle/go/PrintAst.qll b/ql/src/semmle/go/PrintAst.qll new file mode 100644 index 00000000000..d1ded481ca7 --- /dev/null +++ b/ql/src/semmle/go/PrintAst.qll @@ -0,0 +1,195 @@ +/** + * Provides queries to pretty-print a Go AST as a graph. + */ + +import go + +/** + * Hook to customize the functions printed by this module. + */ +class PrintAstConfiguration extends string { + /** + * Restrict to a single string, making this a singleton type. + */ + PrintAstConfiguration() { this = "PrintAstConfiguration" } + + /** + * Holds if the AST for `func` should be printed. By default, holds for all + * functions. + */ + predicate shouldPrintFunction(FuncDef func) { any() } +} + +private predicate shouldPrintFunction(FuncDef func) { + exists(PrintAstConfiguration config | config.shouldPrintFunction(func)) +} + +/** + * An AST node that should be printed. + */ +private newtype TPrintAstNode = + TAstNode(AstNode ast) { + // Do print ast nodes without an enclosing function, e.g. file headers + forall(FuncDef f | f = ast.getEnclosingFunction() | shouldPrintFunction(f)) + } + +/** + * A node in the output tree. + */ +class PrintAstNode extends TPrintAstNode { + /** + * Gets a textual representation of this node. + */ + abstract string toString(); + + /** + * Gets the child node at index `childIndex`. Child indices must be unique, + * but need not be contiguous. + */ + abstract PrintAstNode getChild(int childIndex); + + /** + * Holds if this node should be printed in the output. By default, all nodes + * within a function are printed, but the query can override + * `PrintAstConfiguration.shouldPrintFunction` to filter the output. + */ + predicate shouldPrint() { exists(getLocation()) } + + /** + * Gets a child of this node. + */ + PrintAstNode getAChild() { result = getChild(_) } + + /** + * Gets the location of this node in the source code. + */ + abstract Location getLocation(); + + /** + * Gets the value of the property of this node, where the name of the property + * is `key`. + */ + string getProperty(string key) { + key = "semmle.label" and + result = toString() + } + + /** + * Gets the label for the edge from this node to the specified child. By + * default, this is just the index of the child, but subclasses can override + * this. + */ + string getChildEdgeLabel(int childIndex) { + exists(getChild(childIndex)) and + result = childIndex.toString() + } + + /** + * Gets the `FuncDef` that contains this node. + */ + abstract FuncDef getEnclosingFunction(); +} + +/** + * Gets a pretty-printed representation of the QL class(es) for entity `el`. + */ +private string qlClass(AstNode el) { result = "[" + concat(el.getAQlClass(), ", ") + "] " } + +/** + * Gets a pretty-printed representation of the QL class(es) for entity `el`. + */ +private string qlClassType(Type el) { result = "[" + concat(el.getAQlClass(), ", ") + "] " } + +/** + * Gets a child with the given index and of the given kind, if one exists. + * Note that a given parent can have multiple children with the same index but differing kind. + */ +private AstNode getChildOfKind(AstNode parent, string kind, int i) { + kind = "expr" and result = parent.(ExprParent).getChildExpr(i) + or + kind = "gomodexpr" and result = parent.(GoModExprParent).getChildGoModExpr(i) + or + kind = "stmt" and result = parent.(StmtParent).getChildStmt(i) + or + kind = "decl" and result = parent.(DeclParent).getDecl(i) + or + kind = "spec" and result = parent.(GenDecl).getSpec(i) + or + kind = "field" and fields(result, parent, i) +} + +/** + * Get an AstNode child, ordered by child kind and then by index + */ +private AstNode getUniquelyNumberedChild(AstNode node, int index) { + result = + rank[index + 1](AstNode child, string kind, int i | + child = getChildOfKind(node, kind, i) + | + child order by kind, i + ) +} + +/** + * A graph node representing a real AST node. + */ +class BaseAstNode extends PrintAstNode, TAstNode { + AstNode ast; + + BaseAstNode() { this = TAstNode(ast) } + + override BaseAstNode getChild(int childIndex) { + // Note a node can have several results for getChild(n) because some + // nodes have multiple different types of child (e.g. a File has a + // child expression, the package name, and child declarations whose + // indices may clash), so we renumber them: + result = TAstNode(getUniquelyNumberedChild(ast, childIndex)) + } + + override string toString() { result = qlClass(ast) + ast } + + final override Location getLocation() { result = ast.getLocation() } + + final override FuncDef getEnclosingFunction() { + result = ast or result = ast.getEnclosingFunction() + } +} + +/** + * A node representing an `Expr`. + */ +class ExprNode extends BaseAstNode { + override Expr ast; + + override string getProperty(string key) { + result = super.getProperty(key) + or + key = "Value" and + result = qlClass(ast) + ast.getExactValue() + or + key = "Type" and + not ast.getType() instanceof InvalidType and + result = ast.getType().pp() + } +} + +query predicate nodes(PrintAstNode node, string key, string value) { + node.shouldPrint() and + value = node.getProperty(key) +} + +query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) { + exists(int childIndex | + source.shouldPrint() and + target.shouldPrint() and + target = source.getChild(childIndex) + | + key = "semmle.label" and value = source.getChildEdgeLabel(childIndex) + or + key = "semmle.order" and value = childIndex.toString() + ) +} + +query predicate graphProperties(string key, string value) { + key = "semmle.graphKind" and value = "tree" +} From bd7b7c06b54b8d9762d560e90c271209d83454f9 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 16 Jun 2020 17:18:56 +0100 Subject: [PATCH 2/4] Add AstNode.getCanonicalQlClass and use it in PrintAst This gives those classes satisfied by an AstNode that are considered useful for developer understanding, cf. getAQlClass which returns all satisfied classes and hides overridden ones, even if they are interesting. --- ql/src/semmle/go/AST.qll | 6 ++ ql/src/semmle/go/Comments.qll | 16 +++- ql/src/semmle/go/Decls.qll | 40 ++++++++++ ql/src/semmle/go/Expr.qll | 144 ++++++++++++++++++++++++++++++++-- ql/src/semmle/go/Files.qll | 2 + ql/src/semmle/go/GoMod.qll | 26 +++++- ql/src/semmle/go/PrintAst.qll | 12 +-- ql/src/semmle/go/Stmt.qll | 80 ++++++++++++++++++- 8 files changed, 311 insertions(+), 15 deletions(-) diff --git a/ql/src/semmle/go/AST.qll b/ql/src/semmle/go/AST.qll index a58a8c3d78a..0b283be1ecb 100644 --- a/ql/src/semmle/go/AST.qll +++ b/ql/src/semmle/go/AST.qll @@ -45,6 +45,12 @@ class AstNode extends @node, Locatable { /** Gets the innermost function definition to which this AST node belongs, if any. */ FuncDef getEnclosingFunction() { result = getParent().parentInSameFunction*() } + /** + * Describes important CodeQL classes for this node. May + * return multiple values. + */ + string describeQlClass() { result = "???" } + override string toString() { result = "AST node" } } diff --git a/ql/src/semmle/go/Comments.qll b/ql/src/semmle/go/Comments.qll index 929d68d1315..17bf8e1e512 100644 --- a/ql/src/semmle/go/Comments.qll +++ b/ql/src/semmle/go/Comments.qll @@ -27,6 +27,8 @@ class Comment extends @comment, AstNode { CommentGroup getGroup() { this = result.getAComment() } override string toString() { result = "comment" } + + override string describeQlClass() { result = "Comment" } } /** @@ -59,6 +61,8 @@ class CommentGroup extends @comment_group, AstNode { int getNumComment() { result = count(getAComment()) } override string toString() { result = "comment group" } + + override string describeQlClass() { result = "CommentGroup" } } /** @@ -109,6 +113,8 @@ class DocComment extends CommentGroup { /** Gets the program element documented by this comment group. */ Documentable getDocumentedElement() { result = node } + + override string describeQlClass() { result = "DocComment" } } /** @@ -120,7 +126,9 @@ class DocComment extends CommentGroup { * // Single line comment * ``` */ -class SlashSlashComment extends @slashslashcomment, Comment { } +class SlashSlashComment extends @slashslashcomment, Comment { + override string describeQlClass() { result = "SlashSlashComment" } +} /** * A block comment starting with `/*` and ending with */. @@ -132,7 +140,9 @@ class SlashSlashComment extends @slashslashcomment, Comment { } * comment */ * */ -class SlashStarComment extends @slashstarcomment, Comment { } +class SlashStarComment extends @slashstarcomment, Comment { + override string describeQlClass() { result = "SlashStarComment" } +} /** * A single-line comment starting with `//`. @@ -194,4 +204,6 @@ class BuildConstraintComment extends LineComment { // comment text starts with `+build` getText().regexpMatch("\\s*\\+build.*") } + + override string describeQlClass() { result = "BuildConstraintComment" } } diff --git a/ql/src/semmle/go/Decls.qll b/ql/src/semmle/go/Decls.qll index eec7457df44..73a17604310 100644 --- a/ql/src/semmle/go/Decls.qll +++ b/ql/src/semmle/go/Decls.qll @@ -30,6 +30,8 @@ class Decl extends @decl, ExprParent, StmtParent { */ class BadDecl extends @baddecl, Decl { override string toString() { result = "bad declaration" } + + override string describeQlClass() { result = "BadDecl" } } /** @@ -46,6 +48,8 @@ class GenDecl extends @gendecl, Decl, Documentable { int getNumSpec() { result = count(getASpec()) } override predicate mayHaveSideEffects() { getASpec().mayHaveSideEffects() } + + override string describeQlClass() { result = "GenDecl" } } /** @@ -53,6 +57,8 @@ class GenDecl extends @gendecl, Decl, Documentable { */ class ImportDecl extends @importdecl, GenDecl { override string toString() { result = "import declaration" } + + override string describeQlClass() { result = "ImportDecl" } } /** @@ -60,6 +66,8 @@ class ImportDecl extends @importdecl, GenDecl { */ class ConstDecl extends @constdecl, GenDecl { override string toString() { result = "constant declaration" } + + override string describeQlClass() { result = "ConstDecl" } } /** @@ -67,6 +75,8 @@ class ConstDecl extends @constdecl, GenDecl { */ class TypeDecl extends @typedecl, GenDecl { override string toString() { result = "type declaration" } + + override string describeQlClass() { result = "TypeDecl" } } /** @@ -74,6 +84,8 @@ class TypeDecl extends @typedecl, GenDecl { */ class VarDecl extends @vardecl, GenDecl { override string toString() { result = "variable declaration" } + + override string describeQlClass() { result = "VarDecl" } } /** @@ -133,6 +145,8 @@ class FuncDef extends @funcdef, StmtParent, ExprParent { * Gets a call to this function. */ DataFlow::CallNode getACall() { result.getACallee() = this } + + override string describeQlClass() { result = "FuncDef" } } /** @@ -155,6 +169,8 @@ class FuncDecl extends @funcdecl, Decl, Documentable, FuncDef { DeclaredFunction getFunction() { this = result.getFuncDecl() } override string toString() { result = "function declaration" } + + override string describeQlClass() { result = "FuncDecl" } } /** @@ -219,6 +235,8 @@ class MethodDecl extends FuncDecl { * is the variable `p`. */ ReceiverVariable getReceiver() { result.getFunction() = this } + + override string describeQlClass() { result = "MethodDecl" } } /** @@ -243,6 +261,8 @@ class Spec extends @spec, ExprParent, Documentable { * Memory allocation is not considered an observable side effect. */ predicate mayHaveSideEffects() { none() } + + override string describeQlClass() { result = "Spec" } } /** @@ -262,6 +282,8 @@ class ImportSpec extends @importspec, Spec { string getPath() { result = getPathExpr().getValue() } override string toString() { result = "import specifier" } + + override string describeQlClass() { result = "ImportSpec" } } /** @@ -344,6 +366,8 @@ class ValueSpec extends @valuespec, Spec { override predicate mayHaveSideEffects() { getAnInit().mayHaveSideEffects() } override string toString() { result = "value declaration specifier" } + + override string describeQlClass() { result = "ValueSpec" } } /** @@ -360,6 +384,8 @@ class TypeSpec extends @typespec, Spec { Expr getTypeExpr() { result = getChildExpr(1) } override string toString() { result = "type declaration specifier" } + + override string describeQlClass() { result = "TypeSpec" } } /** @@ -397,6 +423,8 @@ class FieldDecl extends @field, Documentable, ExprParent { StructType getDeclaringType() { result = getDeclaringStructTypeExpr().getType() } override string toString() { result = "field declaration" } + + override string describeQlClass() { result = "FieldDecl" } } /** @@ -404,6 +432,8 @@ class FieldDecl extends @field, Documentable, ExprParent { */ class EmbeddedFieldDecl extends FieldDecl { EmbeddedFieldDecl() { not exists(this.getNameExpr(_)) } + + override string describeQlClass() { result = "EmbeddedFieldDecl" } } /** @@ -453,6 +483,8 @@ class ParameterDecl extends @field, Documentable, ExprParent { } override string toString() { result = "parameter declaration" } + + override string describeQlClass() { result = "ParameterDecl" } } /** @@ -482,6 +514,8 @@ class ReceiverDecl extends @field, Documentable, ExprParent { Expr getNameExpr() { result = getChildExpr(1) } override string toString() { result = "receiver declaration" } + + override string describeQlClass() { result = "ReceiverDecl" } } /** @@ -531,6 +565,8 @@ class ResultVariableDecl extends @field, Documentable, ExprParent { int getIndex() { fields(this, _, -(result + 1)) } override string toString() { result = "result variable declaration" } + + override string describeQlClass() { result = "ResultVariableDecl" } } /** @@ -579,6 +615,8 @@ class MethodSpec extends InterfaceMemberSpec { Expr getNameExpr() { result = name } override string toString() { result = "method declaration" } + + override string describeQlClass() { result = "MethodSpec" } } /** @@ -588,4 +626,6 @@ class EmbeddingSpec extends InterfaceMemberSpec { EmbeddingSpec() { not exists(getChildExpr(1)) } override string toString() { result = "interface embedding" } + + override string describeQlClass() { result = "EmbeddingSpec" } } diff --git a/ql/src/semmle/go/Expr.qll b/ql/src/semmle/go/Expr.qll index 633c46d64a9..fc663441922 100644 --- a/ql/src/semmle/go/Expr.qll +++ b/ql/src/semmle/go/Expr.qll @@ -155,6 +155,8 @@ class Expr extends @expr, ExprParent { */ class BadExpr extends @badexpr, Expr { override string toString() { result = "bad expression" } + + override string describeQlClass() { result = "BadExpr" } } /** @@ -180,6 +182,8 @@ class Ident extends @ident, Expr { predicate refersTo(Entity e) { uses(e) or declares(e) } override string toString() { result = getName() } + + override string describeQlClass() { result = "Ident" } } /** @@ -193,6 +197,8 @@ class Ident extends @ident, Expr { */ class BlankIdent extends Ident { BlankIdent() { getName() = "_" } + + override string describeQlClass() { result = "BlankIdent" } } /** @@ -210,6 +216,8 @@ class Ellipsis extends @ellipsis, Expr { Expr getOperand() { result = getChildExpr(0) } override string toString() { result = "..." } + + override string describeQlClass() { result = "Ellipsis" } } /** @@ -267,7 +275,9 @@ class BasicLit extends @basiclit, Literal { * 256 * ``` */ -class IntLit extends @intlit, BasicLit { } +class IntLit extends @intlit, BasicLit { + override string describeQlClass() { result = "IntLit" } +} /** * A floating-point literal. @@ -278,7 +288,9 @@ class IntLit extends @intlit, BasicLit { } * 2.71828 * ``` */ -class FloatLit extends @floatlit, BasicLit { } +class FloatLit extends @floatlit, BasicLit { + override string describeQlClass() { result = "FloatLit" } +} /** * An imaginary literal. @@ -290,7 +302,9 @@ class FloatLit extends @floatlit, BasicLit { } * 2.7i * ``` */ -class ImagLit extends @imaglit, BasicLit { } +class ImagLit extends @imaglit, BasicLit { + override string describeQlClass() { result = "ImagLit" } +} /** * A rune literal. @@ -312,6 +326,8 @@ class CharLit extends @charlit, BasicLit { // use the constant value of the literal as the string value, as the value we get from the // compiler is an integer, meaning we would not otherwise have a string value for rune literals override string getStringValue() { result = this.getValue() } + + override string describeQlClass() { result = "CharLit" } } class RuneLit = CharLit; @@ -325,7 +341,9 @@ class RuneLit = CharLit; * "hello world" * ``` */ -class StringLit extends @stringlit, BasicLit { } +class StringLit extends @stringlit, BasicLit { + override string describeQlClass() { result = "StringLit" } +} /** * A function literal. @@ -347,6 +365,8 @@ class FuncLit extends @funclit, Literal, StmtParent, FuncDef { override predicate isPlatformIndependentConstant() { any() } override string toString() { result = "function literal" } + + override string describeQlClass() { result = "FuncLit" } } /** @@ -394,6 +414,8 @@ class CompositeLit extends @compositelit, Literal { } override string toString() { result = "composite literal" } + + override string describeQlClass() { result = "CompositeLit" } } /** @@ -417,6 +439,8 @@ class MapLit extends CompositeLit { Type getValueType() { result = mt.getValueType() } override string toString() { result = "map literal" } + + override string describeQlClass() { result = "MapLit" } } /** @@ -439,6 +463,8 @@ class StructLit extends CompositeLit { StructType getStructType() { result = st } override string toString() { result = "struct literal" } + + override string describeQlClass() { result = "StructLit" } } /** @@ -485,6 +511,8 @@ class ArrayLit extends ArrayOrSliceLit { ArrayType getArrayType() { result = type } override string toString() { result = "array literal" } + + override string describeQlClass() { result = "ArrayLit" } } /** @@ -504,6 +532,8 @@ class SliceLit extends ArrayOrSliceLit { SliceType getSliceType() { result = type } override string toString() { result = "slice literal" } + + override string describeQlClass() { result = "SliceLit" } } /** @@ -524,6 +554,8 @@ class ParenExpr extends @parenexpr, Expr { override predicate isPlatformIndependentConstant() { getExpr().isPlatformIndependentConstant() } override string toString() { result = "(...)" } + + override string describeQlClass() { result = "ParenExpr" } } /** @@ -554,6 +586,8 @@ class SelectorExpr extends @selectorexpr, Expr { override predicate mayHaveOwnSideEffects() { any() } override string toString() { result = "selection of " + getSelector() } + + override string describeQlClass() { result = "SelectorExpr" } } /** @@ -575,6 +609,8 @@ class IndexExpr extends @indexexpr, Expr { override predicate mayHaveOwnSideEffects() { any() } override string toString() { result = "index expression" } + + override string describeQlClass() { result = "IndexExpr" } } /** @@ -601,6 +637,8 @@ class SliceExpr extends @sliceexpr, Expr { Expr getMax() { result = getChildExpr(3) } override string toString() { result = "slice expression" } + + override string describeQlClass() { result = "SliceExpr" } } /** @@ -624,6 +662,8 @@ class TypeAssertExpr extends @typeassertexpr, Expr { override predicate isPlatformIndependentConstant() { getExpr().isPlatformIndependentConstant() } override string toString() { result = "type assertion" } + + override string describeQlClass() { result = "TypeAssertExpr" } } /** @@ -641,7 +681,9 @@ class TypeAssertExpr extends @typeassertexpr, Expr { * []byte("x") * ``` */ -class CallOrConversionExpr extends @callorconversionexpr, Expr { } +class CallOrConversionExpr extends @callorconversionexpr, Expr { + override string describeQlClass() { result = "CallOrConversionExpr" } +} /** * A type conversion expression. @@ -666,6 +708,8 @@ class ConversionExpr extends CallOrConversionExpr { } override string toString() { result = "type conversion" } + + override string describeQlClass() { result = "ConversionExpr" } } /** @@ -722,6 +766,8 @@ class CallExpr extends CallOrConversionExpr { not exists(getCalleeName()) and result = "function call" } + + override string describeQlClass() { result = "CallExpr" } } /** @@ -740,6 +786,8 @@ class StarExpr extends @starexpr, Expr { override predicate mayHaveOwnSideEffects() { any() } override string toString() { result = "star expression" } + + override string describeQlClass() { result = "StarExpr" } } /** @@ -762,6 +810,8 @@ class KeyValueExpr extends @keyvalueexpr, Expr { CompositeLit getLiteral() { this = result.getElement(_) } override string toString() { result = "key-value pair" } + + override string describeQlClass() { result = "KeyValueExpr" } } /** @@ -781,6 +831,8 @@ class ArrayTypeExpr extends @arraytypeexpr, TypeExpr { Expr getElement() { result = getChildExpr(1) } override string toString() { result = "array type" } + + override string describeQlClass() { result = "ArrayTypeExpr" } } /** @@ -803,6 +855,8 @@ class StructTypeExpr extends @structtypeexpr, TypeExpr { int getNumField() { result = count(getAField()) } override string toString() { result = "struct type" } + + override string describeQlClass() { result = "StructTypeExpr" } } /** @@ -843,6 +897,8 @@ class FuncTypeExpr extends @functypeexpr, TypeExpr, ScopeNode { ResultVariableDecl getResultDecl() { getNumResult() = 1 and result = getAResultDecl() } override string toString() { result = "function type" } + + override string describeQlClass() { result = "FuncTypeExpr" } } /** @@ -868,6 +924,8 @@ class InterfaceTypeExpr extends @interfacetypeexpr, TypeExpr { int getNumMethod() { result = count(getAMethod()) } override string toString() { result = "interface type" } + + override string describeQlClass() { result = "InterfaceTypeExpr" } } /** @@ -893,6 +951,8 @@ class MapTypeExpr extends @maptypeexpr, TypeExpr { Type getValueType() { result = getValueTypeExpr().getType() } override string toString() { result = "map type" } + + override string describeQlClass() { result = "MapTypeExpr" } } /** @@ -1018,6 +1078,8 @@ class BitwiseUnaryExpr extends @bitwiseunaryexpr, BitwiseExpr, UnaryExpr { } */ class PlusExpr extends @plusexpr, ArithmeticUnaryExpr { override string getOperator() { result = "+" } + + override string describeQlClass() { result = "PlusExpr" } } /** @@ -1031,6 +1093,8 @@ class PlusExpr extends @plusexpr, ArithmeticUnaryExpr { */ class MinusExpr extends @minusexpr, ArithmeticUnaryExpr { override string getOperator() { result = "-" } + + override string describeQlClass() { result = "MinusExpr" } } /** @@ -1044,6 +1108,8 @@ class MinusExpr extends @minusexpr, ArithmeticUnaryExpr { */ class NotExpr extends @notexpr, LogicalUnaryExpr { override string getOperator() { result = "!" } + + override string describeQlClass() { result = "NotExpr" } } /** @@ -1057,6 +1123,8 @@ class NotExpr extends @notexpr, LogicalUnaryExpr { */ class ComplementExpr extends @complementexpr, BitwiseUnaryExpr { override string getOperator() { result = "^" } + + override string describeQlClass() { result = "ComplementExpr" } } /** @@ -1068,6 +1136,8 @@ class DerefExpr extends @derefexpr, UnaryExpr { override predicate mayHaveOwnSideEffects() { any() } override string getOperator() { result = "*" } + + override string describeQlClass() { result = "DerefExpr" } } /** @@ -1083,6 +1153,8 @@ class AddressExpr extends @addressexpr, UnaryExpr { override predicate mayHaveOwnSideEffects() { any() } override string getOperator() { result = "&" } + + override string describeQlClass() { result = "AddressExpr" } } /** @@ -1098,6 +1170,8 @@ class RecvExpr extends @arrowexpr, UnaryExpr { override predicate mayHaveOwnSideEffects() { any() } override string getOperator() { result = "<-" } + + override string describeQlClass() { result = "RecvExpr" } } /** @@ -1243,6 +1317,8 @@ class RelationalComparisonExpr extends @relationalcomparison, ComparisonExpr { */ class LorExpr extends @lorexpr, LogicalBinaryExpr { override string getOperator() { result = "||" } + + override string describeQlClass() { result = "LorExpr" } } class LogOrExpr = LorExpr; @@ -1258,6 +1334,8 @@ class LogOrExpr = LorExpr; */ class LandExpr extends @landexpr, LogicalBinaryExpr { override string getOperator() { result = "&&" } + + override string describeQlClass() { result = "LandExpr" } } class LogAndExpr = LandExpr; @@ -1275,6 +1353,8 @@ class EqlExpr extends @eqlexpr, EqualityTestExpr { override string getOperator() { result = "==" } override boolean getPolarity() { result = true } + + override string describeQlClass() { result = "EqlExpr" } } class EqExpr = EqlExpr; @@ -1292,6 +1372,8 @@ class NeqExpr extends @neqexpr, EqualityTestExpr { override string getOperator() { result = "!=" } override boolean getPolarity() { result = false } + + override string describeQlClass() { result = "NeqExpr" } } /** @@ -1311,6 +1393,8 @@ class LssExpr extends @lssexpr, RelationalComparisonExpr { override Expr getLesserOperand() { result = getLeftOperand() } override Expr getGreaterOperand() { result = getRightOperand() } + + override string describeQlClass() { result = "LssExpr" } } class LTExpr = LssExpr; @@ -1330,6 +1414,8 @@ class LeqExpr extends @leqexpr, RelationalComparisonExpr { override Expr getLesserOperand() { result = getLeftOperand() } override Expr getGreaterOperand() { result = getRightOperand() } + + override string describeQlClass() { result = "LeqExpr" } } class LEExpr = LeqExpr; @@ -1351,6 +1437,8 @@ class GtrExpr extends @gtrexpr, RelationalComparisonExpr { override Expr getLesserOperand() { result = getRightOperand() } override Expr getGreaterOperand() { result = getLeftOperand() } + + override string describeQlClass() { result = "GtrExpr" } } class GTExpr = GtrExpr; @@ -1370,6 +1458,8 @@ class GeqExpr extends @geqexpr, RelationalComparisonExpr { override Expr getLesserOperand() { result = getRightOperand() } override Expr getGreaterOperand() { result = getLeftOperand() } + + override string describeQlClass() { result = "GeqExpr" } } class GEExpr = GeqExpr; @@ -1385,6 +1475,8 @@ class GEExpr = GeqExpr; */ class AddExpr extends @addexpr, ArithmeticBinaryExpr { override string getOperator() { result = "+" } + + override string describeQlClass() { result = "AddExpr" } } /** @@ -1398,6 +1490,8 @@ class AddExpr extends @addexpr, ArithmeticBinaryExpr { */ class SubExpr extends @subexpr, ArithmeticBinaryExpr { override string getOperator() { result = "-" } + + override string describeQlClass() { result = "SubExpr" } } /** @@ -1411,6 +1505,8 @@ class SubExpr extends @subexpr, ArithmeticBinaryExpr { */ class OrExpr extends @orexpr, BitwiseBinaryExpr { override string getOperator() { result = "|" } + + override string describeQlClass() { result = "OrExpr" } } class BitOrExpr = OrExpr; @@ -1426,6 +1522,8 @@ class BitOrExpr = OrExpr; */ class XorExpr extends @xorexpr, BitwiseBinaryExpr { override string getOperator() { result = "^" } + + override string describeQlClass() { result = "XorExpr" } } /** @@ -1439,6 +1537,8 @@ class XorExpr extends @xorexpr, BitwiseBinaryExpr { */ class MulExpr extends @mulexpr, ArithmeticBinaryExpr { override string getOperator() { result = "*" } + + override string describeQlClass() { result = "MulExpr" } } /** @@ -1454,6 +1554,8 @@ class QuoExpr extends @quoexpr, ArithmeticBinaryExpr { override predicate mayHaveOwnSideEffects() { any() } override string getOperator() { result = "/" } + + override string describeQlClass() { result = "QuoExpr" } } class DivExpr = QuoExpr; @@ -1469,6 +1571,8 @@ class DivExpr = QuoExpr; */ class RemExpr extends @remexpr, ArithmeticBinaryExpr { override string getOperator() { result = "%" } + + override string describeQlClass() { result = "RemExpr" } } class ModExpr = RemExpr; @@ -1484,6 +1588,8 @@ class ModExpr = RemExpr; */ class ShlExpr extends @shlexpr, ShiftExpr { override string getOperator() { result = "<<" } + + override string describeQlClass() { result = "ShlExpr" } } class LShiftExpr = ShlExpr; @@ -1499,6 +1605,8 @@ class LShiftExpr = ShlExpr; */ class ShrExpr extends @shrexpr, ShiftExpr { override string getOperator() { result = ">>" } + + override string describeQlClass() { result = "ShrExpr" } } class RShiftExpr = ShrExpr; @@ -1514,6 +1622,8 @@ class RShiftExpr = ShrExpr; */ class AndExpr extends @andexpr, BitwiseBinaryExpr { override string getOperator() { result = "&" } + + override string describeQlClass() { result = "AndExpr" } } class BitAndExpr = AndExpr; @@ -1529,6 +1639,8 @@ class BitAndExpr = AndExpr; */ class AndNotExpr extends @andnotexpr, BitwiseBinaryExpr { override string getOperator() { result = "&^" } + + override string describeQlClass() { result = "AndNotExpr" } } /** @@ -1555,6 +1667,8 @@ class ChanTypeExpr extends @chantypeexpr, TypeExpr { predicate canReceive() { none() } override string toString() { result = "channel type" } + + override string describeQlClass() { result = "ChanTypeExpr" } } /** @@ -1568,6 +1682,8 @@ class ChanTypeExpr extends @chantypeexpr, TypeExpr { */ class SendChanTypeExpr extends @sendchantypeexpr, ChanTypeExpr { override predicate canSend() { any() } + + override string describeQlClass() { result = "SendChanTypeExpr" } } /** @@ -1581,6 +1697,8 @@ class SendChanTypeExpr extends @sendchantypeexpr, ChanTypeExpr { */ class RecvChanTypeExpr extends @recvchantypeexpr, ChanTypeExpr { override predicate canReceive() { any() } + + override string describeQlClass() { result = "RecvChanTypeExpr" } } /** @@ -1596,6 +1714,8 @@ class SendRecvChanTypeExpr extends @sendrcvchantypeexpr, ChanTypeExpr { override predicate canSend() { any() } override predicate canReceive() { any() } + + override string describeQlClass() { result = "SendRecvChanTypeExpr" } } /** @@ -1658,6 +1778,8 @@ class PackageName extends Name { /** Gets the package this name refers to. */ override PackageEntity getTarget() { result = target } + + override string describeQlClass() { result = "PackageName" } } /** @@ -1675,6 +1797,8 @@ class TypeName extends Name { /** Gets the type this name refers to. */ override TypeEntity getTarget() { result = target } + + override string describeQlClass() { result = "TypeName" } } /** @@ -1693,6 +1817,8 @@ class ValueName extends Name { /** Gets the constant, variable or function this name refers to. */ override ValueEntity getTarget() { result = target } + + override string describeQlClass() { result = "ValueName" } } /** @@ -1722,6 +1848,8 @@ class ConstantName extends ValueName { c.getInit().isPlatformIndependentConstant() ) } + + override string describeQlClass() { result = "ConstantName" } } /** @@ -1738,6 +1866,8 @@ class VariableName extends ValueName { /** Gets the variable this name refers to. */ override Variable getTarget() { result = target } + + override string describeQlClass() { result = "VariableName" } } /** @@ -1754,6 +1884,8 @@ class FunctionName extends ValueName { /** Gets the function this name refers to. */ override Function getTarget() { result = target } + + override string describeQlClass() { result = "FunctionName" } } /** @@ -1770,6 +1902,8 @@ class LabelName extends Name { /** Gets the label this name refers to. */ override Label getTarget() { result = target } + + override string describeQlClass() { result = "LabelName" } } /** diff --git a/ql/src/semmle/go/Files.qll b/ql/src/semmle/go/Files.qll index 170ba9c2b3d..9afbf596e6c 100644 --- a/ql/src/semmle/go/Files.qll +++ b/ql/src/semmle/go/Files.qll @@ -207,4 +207,6 @@ class File extends Container, @file, Documentable, ExprParent, GoModExprParent, /** Gets the URL of this file. */ override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } + + override string describeQlClass() { result = "File" } } diff --git a/ql/src/semmle/go/GoMod.qll b/ql/src/semmle/go/GoMod.qll index 63a01b72c14..ca1c4031f70 100644 --- a/ql/src/semmle/go/GoMod.qll +++ b/ql/src/semmle/go/GoMod.qll @@ -12,6 +12,8 @@ class GoModFile extends File { * Gets the module declaration of this file, that is, the line declaring the path of this module. */ GoModModuleLine getModuleDeclaration() { result.getFile() = this } + + override string describeQlClass() { result = "GoModFile" } } /** @@ -38,12 +40,16 @@ class GoModExpr extends @modexpr, GoModExprParent { string getModulePath() { result = this.getFile().getModuleDeclaration().getPath() } override string toString() { result = "go.mod expression" } + + override string describeQlClass() { result = "GoModExpr" } } /** * A top-level block of comments separate from any rule. */ -class GoModCommentBlock extends @modcommentblock, GoModExpr { } +class GoModCommentBlock extends @modcommentblock, GoModExpr { + override string describeQlClass() { result = "GoModCommentBlock" } +} /** * A single line of tokens. @@ -86,6 +92,8 @@ class GoModLine extends @modline, GoModExpr { } override string toString() { result = "go.mod line" } + + override string describeQlClass() { result = "GoModLine" } } /** @@ -107,6 +115,8 @@ class GoModLineBlock extends @modlineblock, GoModExpr { string getRawToken(int i) { modtokens(result, this, i) } override string toString() { result = "go.mod line block" } + + override string describeQlClass() { result = "GoModLineBlock" } } /** @@ -121,6 +131,8 @@ class GoModModuleLine extends GoModLine { string getPath() { result = this.getToken(1) } override string toString() { result = "go.mod module line" } + + override string describeQlClass() { result = "GoModModuleLine" } } /** @@ -133,6 +145,8 @@ class GoModGoLine extends GoModLine { string getVersion() { result = this.getToken(1) } override string toString() { result = "go.mod go line" } + + override string describeQlClass() { result = "GoModGoLine" } } /** @@ -148,6 +162,8 @@ class GoModRequireLine extends GoModLine { string getVersion() { result = this.getToken(2) } override string toString() { result = "go.mod require line" } + + override string describeQlClass() { result = "GoModRequireLine" } } /** @@ -164,6 +180,8 @@ class GoModExcludeLine extends GoModLine { string getVersion() { result = this.getToken(2) } override string toString() { result = "go.mod exclude line" } + + override string describeQlClass() { result = "GoModExcludeLine" } } /** @@ -194,14 +212,20 @@ class GoModReplaceLine extends GoModLine { } override string toString() { result = "go.mod replace line" } + + override string describeQlClass() { result = "GoModReplaceLine" } } /** A left parenthesis for a line block. */ class GoModLParen extends @modlparen, GoModExpr { override string toString() { result = "go.mod (" } + + override string describeQlClass() { result = "GoModLParen" } } /** A right parenthesis for a line block. */ class GoModRParen extends @modrparen, GoModExpr { override string toString() { result = "go.mod )" } + + override string describeQlClass() { result = "GoModRParen" } } diff --git a/ql/src/semmle/go/PrintAst.qll b/ql/src/semmle/go/PrintAst.qll index d1ded481ca7..101303ccb7f 100644 --- a/ql/src/semmle/go/PrintAst.qll +++ b/ql/src/semmle/go/PrintAst.qll @@ -93,12 +93,12 @@ class PrintAstNode extends TPrintAstNode { /** * Gets a pretty-printed representation of the QL class(es) for entity `el`. */ -private string qlClass(AstNode el) { result = "[" + concat(el.getAQlClass(), ", ") + "] " } - -/** - * Gets a pretty-printed representation of the QL class(es) for entity `el`. - */ -private string qlClassType(Type el) { result = "[" + concat(el.getAQlClass(), ", ") + "] " } +private string qlClass(AstNode el) { + // This version shows all non-overridden QL classes: + // result = "[" + concat(el.getAQlClass(), ", ") + "] " + // Normally we prefer to show just the canonical class: + result = "[" + concat(el.describeQlClass(), ", ") + "] " +} /** * Gets a child with the given index and of the given kind, if one exists. diff --git a/ql/src/semmle/go/Stmt.qll b/ql/src/semmle/go/Stmt.qll index 1374b52b801..e47b0fedf1c 100644 --- a/ql/src/semmle/go/Stmt.qll +++ b/ql/src/semmle/go/Stmt.qll @@ -52,6 +52,8 @@ class Stmt extends @stmt, ExprParent, StmtParent { */ class BadStmt extends @badstmt, Stmt { override string toString() { result = "bad statement" } + + override string describeQlClass() { result = "BadStmt" } } /** @@ -72,6 +74,8 @@ class DeclStmt extends @declstmt, Stmt, DeclParent { override predicate mayHaveSideEffects() { getDecl().mayHaveSideEffects() } override string toString() { result = "declaration statement" } + + override string describeQlClass() { result = "DeclStmt" } } /** @@ -85,6 +89,8 @@ class DeclStmt extends @declstmt, Stmt, DeclParent { */ class EmptyStmt extends @emptystmt, Stmt { override string toString() { result = "empty statement" } + + override string describeQlClass() { result = "EmptyStmt" } } /** @@ -109,6 +115,8 @@ class LabeledStmt extends @labeledstmt, Stmt { override predicate mayHaveSideEffects() { getStmt().mayHaveSideEffects() } override string toString() { result = "labeled statement" } + + override string describeQlClass() { result = "LabelledStmt" } } /** @@ -130,6 +138,8 @@ class ExprStmt extends @exprstmt, Stmt { override predicate mayHaveSideEffects() { getExpr().mayHaveSideEffects() } override string toString() { result = "expression statement" } + + override string describeQlClass() { result = "ExprStmt" } } /** @@ -151,6 +161,8 @@ class SendStmt extends @sendstmt, Stmt { override predicate mayHaveSideEffects() { any() } override string toString() { result = "send statement" } + + override string describeQlClass() { result = "SendStmt" } } /** @@ -186,6 +198,8 @@ class IncStmt extends @incstmt, IncDecStmt { override string getOperator() { result = "++" } override string toString() { result = "increment statement" } + + override string describeQlClass() { result = "IncStmt" } } /** @@ -201,6 +215,8 @@ class DecStmt extends @decstmt, IncDecStmt { override string getOperator() { result = "--" } override string toString() { result = "decrement statement" } + + override string describeQlClass() { result = "DecStmt" } } /** @@ -270,7 +286,9 @@ class Assignment extends @assignment, Stmt { * (k) = <-ch // same as: k = <-ch * ``` */ -class SimpleAssignStmt extends @simpleassignstmt, Assignment { } +class SimpleAssignStmt extends @simpleassignstmt, Assignment { + override string describeQlClass() { result = "SimpleAssignStmt" } +} /** * A plain assignment statement. @@ -285,6 +303,8 @@ class SimpleAssignStmt extends @simpleassignstmt, Assignment { } */ class AssignStmt extends @assignstmt, SimpleAssignStmt { override string getOperator() { result = "=" } + + override string describeQlClass() { result = "AssignStmt" } } /** @@ -298,6 +318,8 @@ class AssignStmt extends @assignstmt, SimpleAssignStmt { */ class DefineStmt extends @definestmt, SimpleAssignStmt { override string getOperator() { result = ":=" } + + override string describeQlClass() { result = "DefineStmt" } } /** @@ -323,6 +345,8 @@ class CompoundAssignStmt extends @compoundassignstmt, Assignment { } */ class AddAssignStmt extends @addassignstmt, CompoundAssignStmt { override string getOperator() { result = "+=" } + + override string describeQlClass() { result = "AddAssignStmt" } } /** @@ -336,6 +360,8 @@ class AddAssignStmt extends @addassignstmt, CompoundAssignStmt { */ class SubAssignStmt extends @subassignstmt, CompoundAssignStmt { override string getOperator() { result = "-=" } + + override string describeQlClass() { result = "SubAssignStmt" } } /** @@ -349,6 +375,8 @@ class SubAssignStmt extends @subassignstmt, CompoundAssignStmt { */ class MulAssignStmt extends @mulassignstmt, CompoundAssignStmt { override string getOperator() { result = "*=" } + + override string describeQlClass() { result = "MulAssignStmt" } } /** @@ -362,6 +390,8 @@ class MulAssignStmt extends @mulassignstmt, CompoundAssignStmt { */ class QuoAssignStmt extends @quoassignstmt, CompoundAssignStmt { override string getOperator() { result = "/=" } + + override string describeQlClass() { result = "QuoAssignStmt" } } class DivAssignStmt = QuoAssignStmt; @@ -377,6 +407,8 @@ class DivAssignStmt = QuoAssignStmt; */ class RemAssignStmt extends @remassignstmt, CompoundAssignStmt { override string getOperator() { result = "%=" } + + override string describeQlClass() { result = "RemAssignStmt" } } class ModAssignStmt = RemAssignStmt; @@ -392,6 +424,8 @@ class ModAssignStmt = RemAssignStmt; */ class AndAssignStmt extends @andassignstmt, CompoundAssignStmt { override string getOperator() { result = "&=" } + + override string describeQlClass() { result = "AndAssignStmt" } } /** @@ -405,6 +439,8 @@ class AndAssignStmt extends @andassignstmt, CompoundAssignStmt { */ class OrAssignStmt extends @orassignstmt, CompoundAssignStmt { override string getOperator() { result = "|=" } + + override string describeQlClass() { result = "OrAssignStmt" } } /** @@ -418,6 +454,8 @@ class OrAssignStmt extends @orassignstmt, CompoundAssignStmt { */ class XorAssignStmt extends @xorassignstmt, CompoundAssignStmt { override string getOperator() { result = "^=" } + + override string describeQlClass() { result = "XorAssignStmt" } } /** @@ -431,6 +469,8 @@ class XorAssignStmt extends @xorassignstmt, CompoundAssignStmt { */ class ShlAssignStmt extends @shlassignstmt, CompoundAssignStmt { override string getOperator() { result = "<<=" } + + override string describeQlClass() { result = "ShlAssignStmt" } } class LShiftAssignStmt = ShlAssignStmt; @@ -446,6 +486,8 @@ class LShiftAssignStmt = ShlAssignStmt; */ class ShrAssignStmt extends @shrassignstmt, CompoundAssignStmt { override string getOperator() { result = ">>=" } + + override string describeQlClass() { result = "ShrAssignStmt" } } class RShiftAssignStmt = ShrAssignStmt; @@ -461,6 +503,8 @@ class RShiftAssignStmt = ShrAssignStmt; */ class AndNotAssignStmt extends @andnotassignstmt, CompoundAssignStmt { override string getOperator() { result = "&^=" } + + override string describeQlClass() { result = "AndNotAssignStmt" } } /** @@ -479,6 +523,8 @@ class GoStmt extends @gostmt, Stmt { override predicate mayHaveSideEffects() { getCall().mayHaveSideEffects() } override string toString() { result = "go statement" } + + override string describeQlClass() { result = "GoStmt" } } /** @@ -497,6 +543,8 @@ class DeferStmt extends @deferstmt, Stmt { override predicate mayHaveSideEffects() { getCall().mayHaveSideEffects() } override string toString() { result = "defer statement" } + + override string describeQlClass() { result = "DeferStmt" } } /** @@ -524,6 +572,8 @@ class ReturnStmt extends @returnstmt, Stmt { override predicate mayHaveSideEffects() { getExpr().mayHaveSideEffects() } override string toString() { result = "return statement" } + + override string describeQlClass() { result = "ReturnStmt" } } /** @@ -560,6 +610,8 @@ class BranchStmt extends @branchstmt, Stmt { */ class BreakStmt extends @breakstmt, BranchStmt { override string toString() { result = "break statement" } + + override string describeQlClass() { result = "BreakStmt" } } /** @@ -574,6 +626,8 @@ class BreakStmt extends @breakstmt, BranchStmt { */ class ContinueStmt extends @continuestmt, BranchStmt { override string toString() { result = "continue statement" } + + override string describeQlClass() { result = "ContinueStmt" } } /** @@ -587,6 +641,8 @@ class ContinueStmt extends @continuestmt, BranchStmt { */ class GotoStmt extends @gotostmt, BranchStmt { override string toString() { result = "goto statement" } + + override string describeQlClass() { result = "GotoStmt" } } /** @@ -600,6 +656,8 @@ class GotoStmt extends @gotostmt, BranchStmt { */ class FallthroughStmt extends @fallthroughstmt, BranchStmt { override string toString() { result = "fallthrough statement" } + + override string describeQlClass() { result = "FallthroughStmt" } } /** @@ -627,6 +685,8 @@ class BlockStmt extends @blockstmt, Stmt, ScopeNode { override predicate mayHaveSideEffects() { getAStmt().mayHaveSideEffects() } override string toString() { result = "block statement" } + + override string describeQlClass() { result = "BlockStmt" } } /** @@ -663,6 +723,8 @@ class IfStmt extends @ifstmt, Stmt, ScopeNode { } override string toString() { result = "if statement" } + + override string describeQlClass() { result = "IfStmt" } } /** @@ -707,6 +769,8 @@ class CaseClause extends @caseclause, Stmt, ScopeNode { } override string toString() { result = "case clause" } + + override string describeQlClass() { result = "CaseClause" } } /** @@ -792,6 +856,8 @@ class ExpressionSwitchStmt extends @exprswitchstmt, SwitchStmt { } override string toString() { result = "expression-switch statement" } + + override string describeQlClass() { result = "ExpressionSwitchStmt" } } /** @@ -822,6 +888,8 @@ class TypeSwitchStmt extends @typeswitchstmt, SwitchStmt { override predicate mayHaveSideEffects() { any() } override string toString() { result = "type-switch statement" } + + override string describeQlClass() { result = "TypeSwitchStmt" } } /** @@ -863,6 +931,8 @@ class CommClause extends @commclause, Stmt, ScopeNode { override predicate mayHaveSideEffects() { getAStmt().mayHaveSideEffects() } override string toString() { result = "comm clause" } + + override string describeQlClass() { result = "CommClause" } } /** @@ -890,6 +960,8 @@ class RecvStmt extends Stmt { result = this.(ExprStmt).getExpr() or result = this.(Assignment).getRhs() } + + override string describeQlClass() { result = "RecvStmt" } } /** @@ -950,6 +1022,8 @@ class SelectStmt extends @selectstmt, Stmt { override predicate mayHaveSideEffects() { any() } override string toString() { result = "select statement" } + + override string describeQlClass() { result = "SelectStmt" } } /** @@ -1011,6 +1085,8 @@ class ForStmt extends @forstmt, LoopStmt { } override string toString() { result = "for statement" } + + override string describeQlClass() { result = "ForStmt" } } /** @@ -1051,4 +1127,6 @@ class RangeStmt extends @rangestmt, LoopStmt { override predicate mayHaveSideEffects() { any() } override string toString() { result = "range statement" } + + override string describeQlClass() { result = "RangeStmt" } } From 80b9be10047f220e423cfa3da0dee50fd9e27238 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 17 Jun 2020 14:25:45 +0100 Subject: [PATCH 3/4] Add simple PrintAst test This both checks that many common control-flow structures print as expected, and checks our unique child node numbering, which would otherwise give the same label to a file's package (its 0th child expression) and its 0th declaration. --- .../semmle/go/PrintAst/PrintAst.expected | 592 ++++++++++++++++++ .../semmle/go/PrintAst/PrintAst.ql | 6 + .../library-tests/semmle/go/PrintAst/input.go | 145 +++++ 3 files changed, 743 insertions(+) create mode 100644 ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected create mode 100644 ql/test/library-tests/semmle/go/PrintAst/PrintAst.ql create mode 100644 ql/test/library-tests/semmle/go/PrintAst/input.go diff --git a/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected b/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected new file mode 100644 index 00000000000..7e3e021c2da --- /dev/null +++ b/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected @@ -0,0 +1,592 @@ +input.go: +# 0| [File] /home/chris/codeql-home/codeql-go/ql/test/library-tests/semmle/go/PrintAst/input.go +# 3| 0: [ImportDecl] import declaration +# 3| 0: [ImportSpec] import specifier +# 3| 0: [StringLit] "fmt" +# 8| 1: [FuncDecl] function declaration +# 8| 0: [FunctionName, Ident] test5 +# 8| Type = func(bool) +# 8| 1: [FuncTypeExpr] function type +# 8| 0: [ParameterDecl] parameter declaration +# 8| 0: [Ident, TypeName] bool +# 8| Type = bool +# 8| 1: [Ident, VariableName] b +# 8| Type = bool +# 8| 2: [BlockStmt] block statement +# 9| 0: [BlockStmt] block statement +# 10| 0: [IfStmt] if statement +# 10| 0: [NotExpr] !... +# 10| Type = bool +# 10| 0: [Ident, VariableName] b +# 10| Type = bool +# 10| 1: [BlockStmt] block statement +# 11| 0: [GotoStmt] goto statement +# 11| 0: [Ident, LabelName] outer +# 13| 1: [BlockStmt] block statement +# 15| 2: [EmptyStmt] empty statement +# 18| 1: [ExprStmt] expression statement +# 18| 0: [CallExpr] call to Println +# 18| Type = (int, error) +# 18| 0: [FunctionName, SelectorExpr] selection of Println +# 18| Type = func([]interface { }) int, error +# 18| 0: [Ident, PackageName] fmt +# 18| 1: [FunctionName, Ident] Println +# 18| Type = func([]interface { }) int, error +# 18| 1: [StringLit] "Hi" +# 18| Type = string +# 18| Value = [StringLit] Hi +# 20| 2: [LabelledStmt] labeled statement +# 20| 0: [Ident, LabelName] outer +# 21| 1: [ForStmt] for statement +# 21| 0: [ConstantName, Ident] true +# 21| Type = bool literal +# 21| Value = [ConstantName, Ident] true +# 21| 1: [BlockStmt] block statement +# 22| 0: [ForStmt] for statement +# 22| 0: [LssExpr] ...<... +# 22| Type = bool literal +# 22| 0: [Ident, VariableName] i +# 22| Type = int +# 22| 1: [IntLit] 10 +# 22| Type = int +# 22| Value = [IntLit] 10 +# 22| 1: [DefineStmt] ... := ... +# 22| 0: [Ident, VariableName] i +# 22| Type = int +# 22| 1: [IntLit] 0 +# 22| Type = int +# 22| Value = [IntLit] 0 +# 22| 2: [IncStmt] increment statement +# 22| 0: [Ident, VariableName] i +# 22| Type = int +# 22| 3: [BlockStmt] block statement +# 23| 0: [IfStmt] if statement +# 23| 0: [GtrExpr] ...>... +# 23| Type = bool literal +# 23| 0: [Ident, VariableName] j +# 23| Type = int +# 23| 1: [IntLit] 5 +# 23| Type = int +# 23| Value = [IntLit] 5 +# 23| 1: [DefineStmt] ... := ... +# 23| 0: [Ident, VariableName] j +# 23| Type = int +# 23| 1: [SubExpr] ...-... +# 23| Type = int +# 23| 0: [Ident, VariableName] i +# 23| Type = int +# 23| 1: [IntLit] 1 +# 23| Type = int +# 23| Value = [IntLit] 1 +# 23| 2: [BlockStmt] block statement +# 24| 0: [BreakStmt] break statement +# 24| 0: [Ident, LabelName] outer +# 25| 3: [IfStmt] if statement +# 25| 0: [LssExpr] ...<... +# 25| Type = bool literal +# 25| 0: [Ident, VariableName] i +# 25| Type = int +# 25| 1: [IntLit] 3 +# 25| Type = int +# 25| Value = [IntLit] 3 +# 25| 1: [BlockStmt] block statement +# 26| 0: [BreakStmt] break statement +# 27| 2: [IfStmt] if statement +# 27| 0: [NeqExpr] ...!=... +# 27| Type = bool literal +# 27| 0: [Ident, VariableName] i +# 27| Type = int +# 27| 1: [IntLit] 9 +# 27| Type = int +# 27| Value = [IntLit] 9 +# 27| 1: [BlockStmt] block statement +# 28| 0: [ContinueStmt] continue statement +# 28| 0: [Ident, LabelName] outer +# 29| 2: [IfStmt] if statement +# 29| 0: [GeqExpr] ...>=... +# 29| Type = bool literal +# 29| 0: [Ident, VariableName] i +# 29| Type = int +# 29| 1: [IntLit] 4 +# 29| Type = int +# 29| Value = [IntLit] 4 +# 29| 1: [BlockStmt] block statement +# 30| 0: [GotoStmt] goto statement +# 30| 0: [Ident, LabelName] outer +# 31| 2: [BlockStmt] block statement +# 32| 0: [ContinueStmt] continue statement +# 37| 3: [DefineStmt] ... := ... +# 37| 0: [Ident, VariableName] k +# 37| Type = int +# 37| 1: [IntLit] 9 +# 37| Type = int +# 37| Value = [IntLit] 9 +# 38| 4: [ForStmt] for statement +# 38| 0: [IncStmt] increment statement +# 38| 0: [Ident, VariableName] k +# 38| Type = int +# 38| 1: [BlockStmt] block statement +# 39| 0: [GotoStmt] goto statement +# 39| 0: [Ident, LabelName] outer +# 44| 2: [FuncDecl] function declaration +# 44| 0: [FunctionName, Ident] test6 +# 44| Type = func(chan int, chan float32) +# 44| 1: [FuncTypeExpr] function type +# 44| 0: [ParameterDecl] parameter declaration +# 44| 0: [SendRecvChanTypeExpr] channel type +# 44| Type = chan int +# 44| 0: [Ident, TypeName] int +# 44| Type = int +# 44| 1: [Ident, VariableName] ch1 +# 44| Type = chan int +# 44| 1: [ParameterDecl] parameter declaration +# 44| 0: [SendRecvChanTypeExpr] channel type +# 44| Type = chan float32 +# 44| 0: [Ident, TypeName] float32 +# 44| Type = float32 +# 44| 1: [Ident, VariableName] ch2 +# 44| Type = chan float32 +# 44| 2: [BlockStmt] block statement +# 45| 0: [DeclStmt] declaration statement +# 45| 0: [VarDecl] variable declaration +# 45| 0: [ValueSpec] value declaration specifier +# 45| 0: [Ident, VariableName] a +# 45| Type = [1]float32 +# 45| 1: [ArrayTypeExpr] array type +# 45| Type = [1]float32 +# 45| 0: [IntLit] 1 +# 45| Type = int literal +# 45| Value = [IntLit] 1 +# 45| 1: [Ident, TypeName] float32 +# 45| Type = float32 +# 46| 1: [DeclStmt] declaration statement +# 46| 0: [VarDecl] variable declaration +# 46| 0: [ValueSpec] value declaration specifier +# 46| 0: [Ident, VariableName] w +# 46| Type = bool +# 46| 1: [Ident, TypeName] bool +# 46| Type = bool +# 48| 2: [SelectStmt] select statement +# 48| 0: [BlockStmt] block statement +# 49| 0: [CommClause] comm clause +# 49| 0: [ExprStmt, RecvStmt] expression statement +# 49| 0: [RecvExpr] <-... +# 49| Type = int +# 49| 0: [Ident, VariableName] ch1 +# 49| Type = chan int +# 50| 1: [ExprStmt] expression statement +# 50| 0: [CallExpr] call to Println +# 50| Type = (int, error) +# 50| 0: [FunctionName, SelectorExpr] selection of Println +# 50| Type = func([]interface { }) int, error +# 50| 0: [Ident, PackageName] fmt +# 50| 1: [FunctionName, Ident] Println +# 50| Type = func([]interface { }) int, error +# 50| 1: [StringLit] "Heard from ch1" +# 50| Type = string +# 50| Value = [StringLit] Heard from ch1 +# 51| 1: [CommClause] comm clause +# 51| 0: [AssignStmt, RecvStmt] ... = ... +# 51| 0: [Ident, VariableName] w +# 51| Type = bool +# 51| 1: [IndexExpr] index expression +# 51| Type = float32 +# 51| 0: [Ident, VariableName] a +# 51| Type = [1]float32 +# 51| 1: [IntLit] 0 +# 51| Type = int +# 51| Value = [IntLit] 0 +# 51| 2: [RecvExpr] <-... +# 51| Type = (float32, bool) +# 51| 0: [Ident, VariableName] ch2 +# 51| Type = chan float32 +# 52| 1: [ExprStmt] expression statement +# 52| 0: [CallExpr] call to Println +# 52| Type = (int, error) +# 52| 0: [FunctionName, SelectorExpr] selection of Println +# 52| Type = func([]interface { }) int, error +# 52| 0: [Ident, PackageName] fmt +# 52| 1: [FunctionName, Ident] Println +# 52| Type = func([]interface { }) int, error +# 52| 1: [Ident, VariableName] a +# 52| Type = [1]float32 +# 53| 2: [ExprStmt] expression statement +# 53| 0: [CallExpr] call to Println +# 53| Type = (int, error) +# 53| 0: [FunctionName, SelectorExpr] selection of Println +# 53| Type = func([]interface { }) int, error +# 53| 0: [Ident, PackageName] fmt +# 53| 1: [FunctionName, Ident] Println +# 53| Type = func([]interface { }) int, error +# 53| 1: [Ident, VariableName] w +# 53| Type = bool +# 54| 2: [CommClause] comm clause +# 55| 0: [ExprStmt] expression statement +# 55| 0: [CallExpr] call to Println +# 55| Type = (int, error) +# 55| 0: [FunctionName, SelectorExpr] selection of Println +# 55| Type = func([]interface { }) int, error +# 55| 0: [Ident, PackageName] fmt +# 55| 1: [FunctionName, Ident] Println +# 55| Type = func([]interface { }) int, error +# 56| 3: [CommClause] comm clause +# 56| 0: [SendStmt] send statement +# 56| 0: [Ident, VariableName] ch1 +# 56| Type = chan int +# 56| 1: [IntLit] 42 +# 56| Type = int +# 56| Value = [IntLit] 42 +# 59| 3: [SelectStmt] select statement +# 59| 0: [BlockStmt] block statement +# 63| 3: [FuncDecl] function declaration +# 63| 0: [FunctionName, Ident] test7 +# 63| Type = func(int) int +# 63| 1: [FuncTypeExpr] function type +# 63| 0: [ResultVariableDecl] result variable declaration +# 63| 0: [Ident, TypeName] int +# 63| Type = int +# 63| 1: [ParameterDecl] parameter declaration +# 63| 0: [Ident, TypeName] int +# 63| Type = int +# 63| 1: [Ident, VariableName] x +# 63| Type = int +# 63| 2: [BlockStmt] block statement +# 64| 0: [IfStmt] if statement +# 64| 0: [GtrExpr] ...>... +# 64| Type = bool literal +# 64| 0: [Ident, VariableName] x +# 64| Type = int +# 64| 1: [IntLit] 0 +# 64| Type = int +# 64| Value = [IntLit] 0 +# 64| 1: [BlockStmt] block statement +# 65| 0: [DeferStmt] defer statement +# 65| 0: [CallExpr] function call +# 65| Type = () +# 65| 0: [FuncLit] function literal +# 65| Type = func() +# 65| 0: [FuncTypeExpr] function type +# 65| Type = func() +# 65| 1: [BlockStmt] block statement +# 65| 0: [ExprStmt] expression statement +# 65| 0: [CallExpr] call to Println +# 65| Type = (int, error) +# 65| 0: [FunctionName, SelectorExpr] selection of Println +# 65| Type = func([]interface { }) int, error +# 65| 0: [Ident, PackageName] fmt +# 65| 1: [FunctionName, Ident] Println +# 65| Type = func([]interface { }) int, error +# 65| 1: [Ident, VariableName] x +# 65| Type = int +# 66| 2: [BlockStmt] block statement +# 67| 0: [DeferStmt] defer statement +# 67| 0: [CallExpr] function call +# 67| Type = () +# 67| 0: [FuncLit] function literal +# 67| Type = func() +# 67| 0: [FuncTypeExpr] function type +# 67| Type = func() +# 67| 1: [BlockStmt] block statement +# 67| 0: [ExprStmt] expression statement +# 67| 0: [CallExpr] call to Println +# 67| Type = (int, error) +# 67| 0: [FunctionName, SelectorExpr] selection of Println +# 67| Type = func([]interface { }) int, error +# 67| 0: [Ident, PackageName] fmt +# 67| 1: [FunctionName, Ident] Println +# 67| Type = func([]interface { }) int, error +# 67| 1: [MinusExpr] -... +# 67| Type = int +# 67| 0: [Ident, VariableName] x +# 67| Type = int +# 69| 1: [ReturnStmt] return statement +# 69| 0: [IntLit] 42 +# 69| Type = int +# 69| Value = [IntLit] 42 +# 73| 4: [FuncDecl] function declaration +# 73| 0: [FunctionName, Ident] test8 +# 73| Type = func(int) +# 73| 1: [FuncTypeExpr] function type +# 73| 0: [ParameterDecl] parameter declaration +# 73| 0: [Ident, TypeName] int +# 73| Type = int +# 73| 1: [Ident, VariableName] x +# 73| Type = int +# 73| 2: [BlockStmt] block statement +# 74| 0: [ExpressionSwitchStmt] expression-switch statement +# 74| 0: [Ident, VariableName] x +# 74| Type = int +# 74| 1: [BlockStmt] block statement +# 77| 1: [ExpressionSwitchStmt] expression-switch statement +# 77| 0: [SubExpr] ...-... +# 77| Type = int +# 77| 0: [Ident, VariableName] y +# 77| Type = int +# 77| 1: [IntLit] 19 +# 77| Type = int +# 77| Value = [IntLit] 19 +# 77| 1: [DefineStmt] ... := ... +# 77| 0: [Ident, VariableName] y +# 77| Type = int +# 77| 1: [Ident, VariableName] x +# 77| Type = int +# 77| 2: [BlockStmt] block statement +# 78| 0: [CaseClause] case clause +# 79| 0: [ExprStmt] expression statement +# 79| 0: [CallExpr] call to test5 +# 79| Type = () +# 79| 0: [FunctionName, Ident] test5 +# 79| Type = func(bool) +# 79| 1: [ConstantName, Ident] false +# 79| Type = bool +# 79| Value = [ConstantName, Ident] false +# 82| 2: [ExpressionSwitchStmt] expression-switch statement +# 82| 0: [Ident, VariableName] x +# 82| Type = int +# 82| 1: [BlockStmt] block statement +# 83| 0: [CaseClause] case clause +# 83| 0: [IntLit] 1 +# 83| Type = int +# 83| Value = [IntLit] 1 +# 84| 1: [CaseClause] case clause +# 84| 0: [IntLit] 3 +# 84| Type = int +# 84| Value = [IntLit] 3 +# 84| 1: [IntLit] 2 +# 84| Type = int +# 84| Value = [IntLit] 2 +# 85| 2: [ExprStmt] expression statement +# 85| 0: [CallExpr] call to test5 +# 85| Type = () +# 85| 0: [FunctionName, Ident] test5 +# 85| Type = func(bool) +# 85| 1: [ConstantName, Ident] true +# 85| Type = bool +# 85| Value = [ConstantName, Ident] true +# 88| 3: [ExpressionSwitchStmt] expression-switch statement +# 88| 0: [Ident, VariableName] x +# 88| Type = int +# 88| 1: [BlockStmt] block statement +# 89| 0: [CaseClause] case clause +# 89| 0: [IntLit] 1 +# 89| Type = int +# 89| Value = [IntLit] 1 +# 90| 1: [ExprStmt] expression statement +# 90| 0: [CallExpr] call to test5 +# 90| Type = () +# 90| 0: [FunctionName, Ident] test5 +# 90| Type = func(bool) +# 90| 1: [ConstantName, Ident] false +# 90| Type = bool +# 90| Value = [ConstantName, Ident] false +# 91| 2: [FallthroughStmt] fallthrough statement +# 92| 1: [CaseClause] case clause +# 92| 0: [SubExpr] ...-... +# 92| Type = int +# 92| Value = [SubExpr] -3 +# 92| 0: [IntLit] 2 +# 92| Type = int literal +# 92| Value = [IntLit] 2 +# 92| 1: [IntLit] 5 +# 92| Type = int literal +# 92| Value = [IntLit] 5 +# 93| 1: [ExprStmt] expression statement +# 93| 0: [CallExpr] call to test5 +# 93| Type = () +# 93| 0: [FunctionName, Ident] test5 +# 93| Type = func(bool) +# 93| 1: [ConstantName, Ident] true +# 93| Type = bool +# 93| Value = [ConstantName, Ident] true +# 96| 4: [ExpressionSwitchStmt] expression-switch statement +# 96| 0: [Ident, VariableName] x +# 96| Type = int +# 96| 1: [BlockStmt] block statement +# 97| 0: [CaseClause] case clause +# 98| 1: [CaseClause] case clause +# 98| 0: [IntLit] 2 +# 98| Type = int +# 98| Value = [IntLit] 2 +# 99| 1: [ExprStmt] expression statement +# 99| 0: [CallExpr] call to test5 +# 99| Type = () +# 99| 0: [FunctionName, Ident] test5 +# 99| Type = func(bool) +# 99| 1: [ConstantName, Ident] true +# 99| Type = bool +# 99| Value = [ConstantName, Ident] true +# 102| 5: [ExpressionSwitchStmt] expression-switch statement +# 102| 0: [BlockStmt] block statement +# 103| 0: [CaseClause] case clause +# 104| 0: [BreakStmt] break statement +# 105| 1: [CaseClause] case clause +# 105| 0: [ConstantName, Ident] true +# 105| Type = bool +# 105| Value = [ConstantName, Ident] true +# 110| 5: [FuncDecl] function declaration +# 110| 0: [FunctionName, Ident] test9 +# 110| Type = func(interface { }) +# 110| 1: [FuncTypeExpr] function type +# 110| 0: [ParameterDecl] parameter declaration +# 110| 0: [InterfaceTypeExpr] interface type +# 110| Type = interface { } +# 110| 1: [Ident, VariableName] x +# 110| Type = interface { } +# 110| 2: [BlockStmt] block statement +# 111| 0: [TypeSwitchStmt] type-switch statement +# 111| 0: [DefineStmt] ... := ... +# 111| 0: [Ident] y +# 111| 1: [TypeAssertExpr] type assertion +# 111| 0: [Ident, VariableName] x +# 111| Type = interface { } +# 111| 1: [BlockStmt] block statement +# 112| 0: [CaseClause] case clause +# 112| 0: [Ident, TypeName] string +# 112| Type = string +# 112| 1: [Ident, TypeName] error +# 112| Type = error +# 113| 2: [ExprStmt] expression statement +# 113| 0: [CallExpr] call to Println +# 113| Type = (int, error) +# 113| 0: [FunctionName, SelectorExpr] selection of Println +# 113| Type = func([]interface { }) int, error +# 113| 0: [Ident, PackageName] fmt +# 113| 1: [FunctionName, Ident] Println +# 113| Type = func([]interface { }) int, error +# 113| 1: [Ident, VariableName] y +# 113| Type = interface { } +# 114| 1: [CaseClause] case clause +# 114| 0: [Ident, TypeName] float32 +# 114| Type = float32 +# 115| 1: [ExprStmt] expression statement +# 115| 0: [CallExpr] call to test5 +# 115| Type = () +# 115| 0: [FunctionName, Ident] test5 +# 115| Type = func(bool) +# 115| 1: [ConstantName, Ident] true +# 115| Type = bool +# 115| Value = [ConstantName, Ident] true +# 116| 2: [ExprStmt] expression statement +# 116| 0: [CallExpr] call to test5 +# 116| Type = () +# 116| 0: [FunctionName, Ident] test5 +# 116| Type = func(bool) +# 116| 1: [ConstantName, Ident] false +# 116| Type = bool +# 116| Value = [ConstantName, Ident] false +# 119| 1: [TypeSwitchStmt] type-switch statement +# 119| 0: [DefineStmt] ... := ... +# 119| 0: [Ident, VariableName] y +# 119| Type = interface { } +# 119| 1: [Ident, VariableName] x +# 119| Type = interface { } +# 119| 1: [ExprStmt] expression statement +# 119| 0: [TypeAssertExpr] type assertion +# 119| 0: [Ident, VariableName] y +# 119| Type = interface { } +# 119| 2: [BlockStmt] block statement +# 120| 0: [CaseClause] case clause +# 121| 0: [ExprStmt] expression statement +# 121| 0: [CallExpr] call to test5 +# 121| Type = () +# 121| 0: [FunctionName, Ident] test5 +# 121| Type = func(bool) +# 121| 1: [ConstantName, Ident] false +# 121| Type = bool +# 121| Value = [ConstantName, Ident] false +# 126| 6: [FuncDecl] function declaration +# 126| 0: [FunctionName, Ident] test10 +# 126| Type = func(func() ) +# 126| 1: [FuncTypeExpr] function type +# 126| 0: [ParameterDecl] parameter declaration +# 126| 0: [FuncTypeExpr] function type +# 126| Type = func() +# 126| 1: [Ident, VariableName] f +# 126| Type = func() +# 126| 2: [BlockStmt] block statement +# 127| 0: [GoStmt] go statement +# 127| 0: [CallExpr] call to f +# 127| Type = () +# 127| 0: [Ident, VariableName] f +# 127| Type = func() +# 131| 7: [FuncDecl] function declaration +# 131| 0: [FunctionName, Ident] test11 +# 131| Type = func([]int) +# 131| 1: [FuncTypeExpr] function type +# 131| 0: [ParameterDecl] parameter declaration +# 131| 0: [ArrayTypeExpr] array type +# 131| Type = []int +# 131| 0: [Ident, TypeName] int +# 131| Type = int +# 131| 1: [Ident, VariableName] xs +# 131| Type = []int +# 131| 2: [BlockStmt] block statement +# 132| 0: [RangeStmt] range statement +# 132| 0: [Ident, VariableName] x +# 132| Type = int +# 132| 1: [Ident, VariableName] xs +# 132| Type = []int +# 132| 2: [BlockStmt] block statement +# 133| 0: [IfStmt] if statement +# 133| 0: [GtrExpr] ...>... +# 133| Type = bool literal +# 133| 0: [Ident, VariableName] x +# 133| Type = int +# 133| 1: [IntLit] 5 +# 133| Type = int +# 133| Value = [IntLit] 5 +# 133| 1: [BlockStmt] block statement +# 134| 0: [ContinueStmt] continue statement +# 136| 1: [ExprStmt] expression statement +# 136| 0: [CallExpr] call to Print +# 136| Type = (int, error) +# 136| 0: [FunctionName, SelectorExpr] selection of Print +# 136| Type = func([]interface { }) int, error +# 136| 0: [Ident, PackageName] fmt +# 136| 1: [FunctionName, Ident] Print +# 136| Type = func([]interface { }) int, error +# 136| 1: [Ident, VariableName] x +# 136| Type = int +# 139| 1: [RangeStmt] range statement +# 139| 0: [Ident, VariableName] i +# 139| Type = int +# 139| 1: [Ident, VariableName] v +# 139| Type = int +# 139| 2: [Ident, VariableName] xs +# 139| Type = []int +# 139| 3: [BlockStmt] block statement +# 140| 0: [ExprStmt] expression statement +# 140| 0: [CallExpr] call to Print +# 140| Type = (int, error) +# 140| 0: [FunctionName, SelectorExpr] selection of Print +# 140| Type = func([]interface { }) int, error +# 140| 0: [Ident, PackageName] fmt +# 140| 1: [FunctionName, Ident] Print +# 140| Type = func([]interface { }) int, error +# 140| 1: [Ident, VariableName] i +# 140| Type = int +# 140| 2: [Ident, VariableName] v +# 140| Type = int +# 143| 2: [RangeStmt] range statement +# 143| 0: [Ident, VariableName] xs +# 143| Type = []int +# 143| 1: [BlockStmt] block statement +# 1| 8: [Ident] main +# 7| [DocComment] comment group +# 43| [DocComment] comment group +# 62| [DocComment] comment group +# 72| [DocComment] comment group +# 109| [DocComment] comment group +# 125| [DocComment] comment group +# 130| [DocComment] comment group +# 5| [CommentGroup] comment group +# 5| [SlashSlashComment] comment +# 7| [SlashSlashComment] comment +# 15| [CommentGroup] comment group +# 15| [SlashSlashComment] comment +# 43| [SlashSlashComment] comment +# 62| [SlashSlashComment] comment +# 72| [SlashSlashComment] comment +# 109| [SlashSlashComment] comment +# 125| [SlashSlashComment] comment +# 130| [SlashSlashComment] comment diff --git a/ql/test/library-tests/semmle/go/PrintAst/PrintAst.ql b/ql/test/library-tests/semmle/go/PrintAst/PrintAst.ql new file mode 100644 index 00000000000..e5886380dc2 --- /dev/null +++ b/ql/test/library-tests/semmle/go/PrintAst/PrintAst.ql @@ -0,0 +1,6 @@ +/** + * @kind graph + */ + +import go +import semmle.go.PrintAst diff --git a/ql/test/library-tests/semmle/go/PrintAst/input.go b/ql/test/library-tests/semmle/go/PrintAst/input.go new file mode 100644 index 00000000000..f9fddbd5504 --- /dev/null +++ b/ql/test/library-tests/semmle/go/PrintAst/input.go @@ -0,0 +1,145 @@ +package main + +import "fmt" + +// NOTE: after auto-formatting this file, make sure to put back the empty statement on line 15 below + +// simple statements and for loops +func test5(b bool) { + { + if !b { + goto outer + } + { + } + ; // empty statement + } + + fmt.Println("Hi") + +outer: + for true { + for i := 0; i < 10; i++ { + if j := i - 1; j > 5 { + break outer + } else if i < 3 { + break + } else if i != 9 { + continue outer + } else if i >= 4 { + goto outer + } else { + continue + } + } + } + + k := 9 + for ; ; k++ { + goto outer + } +} + +// select +func test6(ch1 chan int, ch2 chan float32) { + var a [1]float32 + var w bool + + select { + case <-ch1: + fmt.Println("Heard from ch1") + case a[0], w = <-ch2: + fmt.Println(a) + fmt.Println(w) + default: + fmt.Println() + case ch1 <- 42: + } + + select {} +} + +// defer +func test7(x int) int { + if x > 0 { + defer func() { fmt.Println(x) }() + } else { + defer func() { fmt.Println(-x) }() + } + return 42 +} + +// expression switch +func test8(x int) { + switch x { + } + + switch y := x; y - 19 { + default: + test5(false) + } + + switch x { + case 1: + case 2, 3: + test5(true) + } + + switch x { + case 1: + test5(false) + fallthrough + case 2 - 5: + test5(true) + } + + switch x { + default: + case 2: + test5(true) + } + + switch { + default: + break + case true: + } +} + +// type switch +func test9(x interface{}) { + switch y := x.(type) { + case error, string: + fmt.Println(y) + case float32: + test5(true) + test5(false) + } + + switch y := x; y.(type) { + default: + test5(false) + } +} + +// go +func test10(f func()) { + go f() +} + +// more loops +func test11(xs []int) { + for x := range xs { + if x > 5 { + continue + } + fmt.Print(x) + } + + for i, v := range xs { + fmt.Print(i, v) + } + + for range xs { + } +} From 1a823b21f149bbc4cb782da8589499b42e40f185 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 17 Jun 2020 15:03:29 +0100 Subject: [PATCH 4/4] PrintAst: Emit relative paths for file nodes This is a workaround for codeql run test not itself truncating absolute paths when comparing against actual output. --- ql/src/semmle/go/PrintAst.qll | 14 ++++++++++++++ .../semmle/go/PrintAst/PrintAst.expected | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ql/src/semmle/go/PrintAst.qll b/ql/src/semmle/go/PrintAst.qll index 101303ccb7f..b425d475f15 100644 --- a/ql/src/semmle/go/PrintAst.qll +++ b/ql/src/semmle/go/PrintAst.qll @@ -173,6 +173,20 @@ class ExprNode extends BaseAstNode { } } +/** + * A node representing a `File` + */ +class FileNode extends BaseAstNode { + override File ast; + + /** + * Gets the string representation of this File. Note explicitly using a relative path + * like this rather than absolute as per default for the File class is a workaround for + * a bug with codeql run test, which should replace absolute paths but currently does not. + */ + override string toString() { result = qlClass(ast) + ast.getRelativePath() } +} + query predicate nodes(PrintAstNode node, string key, string value) { node.shouldPrint() and value = node.getProperty(key) diff --git a/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected b/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected index 7e3e021c2da..bd1454dbe7f 100644 --- a/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected +++ b/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected @@ -1,5 +1,5 @@ input.go: -# 0| [File] /home/chris/codeql-home/codeql-go/ql/test/library-tests/semmle/go/PrintAst/input.go +# 0| [File] library-tests/semmle/go/PrintAst/input.go # 3| 0: [ImportDecl] import declaration # 3| 0: [ImportSpec] import specifier # 3| 0: [StringLit] "fmt"