mirror of
https://github.com/github/codeql.git
synced 2026-01-29 14:23:03 +01:00
Add support for extracting Go frontend errors.
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
gotypes "go/types"
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
var defaultSnippet = AddDefaultSnippet(`
|
||||
@@ -642,6 +643,20 @@ var ModLParenType = ModExprKind.NewBranch("@modlparen")
|
||||
// ModRParenType is the type of go.mod line block end AST nodes
|
||||
var ModRParenType = ModExprKind.NewBranch("@modrparen")
|
||||
|
||||
// ErrorType is the type of frontend errors
|
||||
var ErrorType = NewPrimaryKeyType("@error")
|
||||
|
||||
// ErrorKind is a case type for distinguishing different kinds of frontend errors
|
||||
var ErrorKind = NewCaseType(ErrorType, "kind")
|
||||
|
||||
// ErrorTypes is a map from error kinds to the corresponding type
|
||||
var ErrorTypes = map[packages.ErrorKind]*BranchType{
|
||||
packages.UnknownError: ErrorKind.NewBranch("@unknownerror"),
|
||||
packages.ListError: ErrorKind.NewBranch("@listerror"),
|
||||
packages.ParseError: ErrorKind.NewBranch("@parseerror"),
|
||||
packages.TypeError: ErrorKind.NewBranch("@typeerror"),
|
||||
}
|
||||
|
||||
// LocationsDefaultTable is the table defining location objects
|
||||
var LocationsDefaultTable = NewTable("locations_default",
|
||||
EntityColumn(LocationDefaultType, "id").Key(),
|
||||
@@ -915,3 +930,16 @@ var ModTokensTable = NewTable("modtokens",
|
||||
EntityColumn(ModExprType, "parent"),
|
||||
IntColumn("idx"),
|
||||
).KeySet("parent", "idx")
|
||||
|
||||
// ErrorsTable is the table describing frontend errors
|
||||
var ErrorsTable = NewTable("errors",
|
||||
EntityColumn(ErrorType, "id").Key(),
|
||||
IntColumn("kind"),
|
||||
StringColumn("msg"),
|
||||
StringColumn("rawpos"),
|
||||
StringColumn("file"),
|
||||
IntColumn("line"),
|
||||
IntColumn("col"),
|
||||
EntityColumn(PackageType, "package"),
|
||||
IntColumn("idx"),
|
||||
).KeySet("package", "idx")
|
||||
|
||||
@@ -57,13 +57,6 @@ func ExtractWithFlags(buildFlags []string, patterns []string) error {
|
||||
packages.Visit(pkgs, func(pkg *packages.Package) bool {
|
||||
return true
|
||||
}, func(pkg *packages.Package) {
|
||||
if len(pkg.Errors) != 0 {
|
||||
log.Printf("Warning: encountered errors extracting package `%s`:", pkg.PkgPath)
|
||||
for _, err := range pkg.Errors {
|
||||
log.Printf(" %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
tw, err := trap.NewWriter(pkg.PkgPath, pkg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -74,6 +67,14 @@ func ExtractWithFlags(buildFlags []string, patterns []string) error {
|
||||
tw.ForEachObject(extractObjectType)
|
||||
lbl := tw.Labeler.GlobalID(pkg.PkgPath + ";pkg")
|
||||
dbscheme.PackagesTable.Emit(tw, lbl, pkg.Name, pkg.PkgPath, scope)
|
||||
|
||||
if len(pkg.Errors) != 0 {
|
||||
log.Printf("Warning: encountered errors extracting package `%s`:", pkg.PkgPath)
|
||||
for i, err := range pkg.Errors {
|
||||
log.Printf(" %s", err.Error())
|
||||
extractError(tw, err, lbl, i)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// this sets the number of threads that the Go runtime will spawn; this is separate
|
||||
@@ -253,6 +254,43 @@ func extractObjectType(tw *trap.Writer, obj types.Object, lbl trap.Label) {
|
||||
}
|
||||
}
|
||||
|
||||
// extractError extracts the message and location of a frontend error
|
||||
func extractError(tw *trap.Writer, err packages.Error, pkglbl trap.Label, idx int) {
|
||||
var (
|
||||
lbl = tw.Labeler.FreshID()
|
||||
kind = dbscheme.ErrorTypes[err.Kind].Index()
|
||||
pos = err.Pos
|
||||
posComponents = strings.Split(err.Pos, ":")
|
||||
file = ""
|
||||
line = 0
|
||||
col = 0
|
||||
e error
|
||||
)
|
||||
switch len(posComponents) {
|
||||
case 3:
|
||||
// "file:line:col"
|
||||
col, e = strconv.Atoi(posComponents[2])
|
||||
if e != nil {
|
||||
log.Printf("Warning: malformed column number `%s`: %v", posComponents[2], e)
|
||||
}
|
||||
fallthrough
|
||||
case 2:
|
||||
// "file:line"
|
||||
file = posComponents[0]
|
||||
line, e = strconv.Atoi(posComponents[1])
|
||||
if e != nil {
|
||||
log.Printf("Warning: malformed line number `%s`: %v", posComponents[1], e)
|
||||
}
|
||||
default:
|
||||
// "", "-"
|
||||
if pos != "" && pos != "-" {
|
||||
log.Printf("Warning: malformed error position `%s`", pos)
|
||||
}
|
||||
}
|
||||
file = filepath.ToSlash(srcarchive.TransformPath(file))
|
||||
dbscheme.ErrorsTable.Emit(tw, lbl, kind, err.Msg, pos, file, line, col, pkglbl, idx)
|
||||
}
|
||||
|
||||
// extractPackage extracts AST information for all files in the given package
|
||||
func extractPackage(pkg *packages.Package, wg *sync.WaitGroup,
|
||||
goroutineSem *semaphore, fdSem *semaphore) {
|
||||
|
||||
@@ -124,6 +124,10 @@ modexprs(unique int id: @modexpr, int kind: int ref, int parent: @modexprparent
|
||||
#keyset[parent, idx]
|
||||
modtokens(string token: string ref, int parent: @modexpr ref, int idx: int ref);
|
||||
|
||||
#keyset[package, idx]
|
||||
errors(unique int id: @error, int kind: int ref, string msg: string ref, string rawpos: string ref,
|
||||
string file: string ref, int line: int ref, int col: int ref, int package: @package ref, int idx: int ref);
|
||||
|
||||
@container = @file | @folder;
|
||||
|
||||
@locatable = @node | @localscope;
|
||||
@@ -418,3 +422,9 @@ case @modexpr.kind of
|
||||
| 3 = @modlparen
|
||||
| 4 = @modrparen;
|
||||
|
||||
case @error.kind of
|
||||
0 = @unknownerror
|
||||
| 1 = @listerror
|
||||
| 2 = @parseerror
|
||||
| 3 = @typeerror;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user