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.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..b425d475f15 --- /dev/null +++ b/ql/src/semmle/go/PrintAst.qll @@ -0,0 +1,209 @@ +/** + * 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) { + // 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. + * 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() + } +} + +/** + * 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) +} + +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" +} 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" } } 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..bd1454dbe7f --- /dev/null +++ b/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected @@ -0,0 +1,592 @@ +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" +# 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 { + } +}