const Header … const Full … // Parse parses a buffer of Go source, repairing the tree if necessary. // // The provided ctx is used only for logging. func Parse(ctx context.Context, fset *token.FileSet, uri protocol.DocumentURI, src []byte, mode parser.Mode, purgeFuncBodies bool) (res *File, fixes []fixType) { … } // fixAST inspects the AST and potentially modifies any *ast.BadStmts so that it can be // type-checked more effectively. // // If fixAST returns true, the resulting AST is considered "fixed", meaning // positions have been mangled, and type checker errors may not make sense. func fixAST(n ast.Node, tok *token.File, src []byte) (fixes []fixType) { … } // walkASTWithParent walks the AST rooted at n. The semantics are // similar to ast.Inspect except it does not call f(nil). func walkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) { … } type fixType … const noFix … const fixedCurlies … const fixedDanglingSelector … const fixedDeferOrGo … const fixedArrayType … const fixedInit … const fixedPhantomSelector … const fixedEmptySwitch … // fixSrc attempts to modify the file's source code to fix certain // syntax errors that leave the rest of the file unparsed. // // fixSrc returns a non-nil result if and only if a fix was applied. func fixSrc(f *ast.File, tf *token.File, src []byte) (newSrc []byte, fix fixType) { … } // fixMissingCurlies adds in curly braces for block statements that // are missing curly braces. For example: // // if foo // // becomes // // if foo {} func fixMissingCurlies(f *ast.File, b *ast.BlockStmt, parent ast.Node, tok *token.File, src []byte) []byte { … } // fixEmptySwitch moves empty switch/select statements' closing curly // brace down one line. This allows us to properly detect incomplete // "case" and "default" keywords as inside the switch statement. For // example: // // switch { // def<> // } // // gets parsed like: // // switch { // } // // Later we manually pull out the "def" token, but we need to detect // that our "<>" position is inside the switch block. To do that we // move the curly brace so it looks like: // // switch { // // } // // The resulting bool reports whether any fixing occurred. func fixEmptySwitch(body *ast.BlockStmt, tok *token.File, src []byte) bool { … } // fixDanglingSelector inserts real "_" selector expressions in place // of phantom "_" selectors. For example: // // func _() { // x.<> // } // // var x struct { i int } // // To fix completion at "<>", we insert a real "_" after the "." so the // following declaration of "x" can be parsed and type checked // normally. func fixDanglingSelector(s *ast.SelectorExpr, tf *token.File, src []byte) []byte { … } // fixPhantomSelector tries to fix selector expressions with phantom // "_" selectors. In particular, we check if the selector is a // keyword, and if so we swap in an *ast.Ident with the keyword text. For example: // // foo.var // // yields a "_" selector instead of "var" since "var" is a keyword. // // TODO(rfindley): should this constitute an ast 'fix'? // // The resulting bool reports whether any fixing occurred. func fixPhantomSelector(sel *ast.SelectorExpr, tf *token.File, src []byte) bool { … } // isPhantomUnderscore reports whether the given ident is a phantom // underscore. The parser sometimes inserts phantom underscores when // it encounters otherwise unparseable situations. func isPhantomUnderscore(id *ast.Ident, tok *token.File, src []byte) bool { … } // fixInitStmt fixes cases where the parser misinterprets an // if/for/switch "init" statement as the "cond" conditional. In cases // like "if i := 0" the user hasn't typed the semicolon yet so the // parser is looking for the conditional expression. However, "i := 0" // are not valid expressions, so we get a BadExpr. // // The resulting bool reports whether any fixing occurred. func fixInitStmt(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte) bool { … } // readKeyword reads the keyword starting at pos, if any. func readKeyword(pos token.Pos, tok *token.File, src []byte) string { … } // fixArrayType tries to parse an *ast.BadExpr into an *ast.ArrayType. // go/parser often turns lone array types like "[]int" into BadExprs // if it isn't expecting a type. func fixArrayType(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte) bool { … } // precedingToken scans src to find the token preceding pos. func precedingToken(pos token.Pos, tok *token.File, src []byte) token.Token { … } // fixDeferOrGoStmt tries to parse an *ast.BadStmt into a defer or a go statement. // // go/parser packages a statement of the form "defer x." as an *ast.BadStmt because // it does not include a call expression. This means that go/types skips type-checking // this statement entirely, and we can't use the type information when completing. // Here, we try to generate a fake *ast.DeferStmt or *ast.GoStmt to put into the AST, // instead of the *ast.BadStmt. func fixDeferOrGoStmt(bad *ast.BadStmt, parent ast.Node, tok *token.File, src []byte) bool { … } // parseStmt parses the statement in src and updates its position to // start at pos. // // tok is the original file containing pos. Used to ensure that all adjusted // positions are valid. func parseStmt(tok *token.File, pos token.Pos, src []byte) (ast.Stmt, error) { … } // parseExpr parses the expression in src and updates its position to // start at pos. func parseExpr(tok *token.File, pos token.Pos, src []byte) (ast.Expr, error) { … } var tokenPosType … // offsetPositions applies an offset to the positions in an ast.Node. func offsetPositions(tok *token.File, n ast.Node, offset token.Pos) { … } // replaceNode updates parent's child oldChild to be newChild. It // returns whether it replaced successfully. func replaceNode(parent, oldChild, newChild ast.Node) bool { … }