Skip to content

Commit 2d1fc75

Browse files
author
Adam Welc
committed
Very early prototype of Go frontend for Infer capable of analyzing a few very simple code examples (build using "build-infer.sh go" with Go programming environment already pre-installed)
1 parent 5616940 commit 2d1fc75

32 files changed

+885
-26
lines changed

Makefile.autoconf.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ bindir = @bindir@
1111
BUCK = @BUCK@
1212
BUILD_C_ANALYZERS = @BUILD_C_ANALYZERS@
1313
BUILD_JAVA_ANALYZERS = @BUILD_JAVA_ANALYZERS@
14+
BUILD_GO_ANALYZERS = @BUILD_GO_ANALYZERS@
1415
CAML_LD_LIBRARY_PATH = @CAML_LD_LIBRARY_PATH@
1516
CC = @CC@
1617
CFLAGS = @CFLAGS@

build-infer.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ function usage() {
2525
echo " all build everything (default)"
2626
echo " clang build C and Objective-C analyzer"
2727
echo " java build Java analyzer"
28+
echo " go build Go analyzer"
2829
echo
2930
echo " options:"
3031
echo " -h,--help show this message"
@@ -42,6 +43,7 @@ function usage() {
4243
# arguments
4344
BUILD_CLANG=${BUILD_CLANG:-no}
4445
BUILD_JAVA=${BUILD_JAVA:-no}
46+
BUILD_GO=${BUILD_GO:-no}
4547
INFER_CONFIGURE_OPTS=${INFER_CONFIGURE_OPTS:-""}
4648
INFER_OPAM_SWITCH=${INFER_OPAM_SWITCH:-$INFER_OPAM_SWITCH_DEFAULT}
4749
INTERACTIVE=${INTERACTIVE:-yes}
@@ -58,6 +60,7 @@ while [[ $# > 0 ]]; do
5860
all)
5961
BUILD_CLANG=yes
6062
BUILD_JAVA=yes
63+
BUILD_GO=yes
6164
shift
6265
continue
6366
;;
@@ -71,6 +74,11 @@ while [[ $# > 0 ]]; do
7174
shift
7275
continue
7376
;;
77+
go)
78+
BUILD_GO=yes
79+
shift
80+
continue
81+
;;
7482
-h|--help)
7583
usage
7684
exit 0
@@ -103,9 +111,10 @@ while [[ $# > 0 ]]; do
103111
done
104112

105113
# if no arguments then build both clang and Java
106-
if [ "$BUILD_CLANG" == "no" ] && [ "$BUILD_JAVA" == "no" ]; then
114+
if [ "$BUILD_CLANG" == "no" ] && [ "$BUILD_JAVA" == "no" ] && [ "$BUILD_GO" == "no" ]; then
107115
BUILD_CLANG=yes
108116
BUILD_JAVA=yes
117+
BUILD_GO=yes
109118
fi
110119

111120
# enable --yes option for some commands in non-interactive mode
@@ -159,6 +168,9 @@ fi
159168
if [ "$BUILD_JAVA" == "no" ]; then
160169
INFER_CONFIGURE_OPTS+=" --disable-java-analyzers"
161170
fi
171+
if [ "$BUILD_GO" = "no" ]; then
172+
INFER_CONFIGURE_OPTS+=" --disable-go-analyzers"
173+
fi
162174

163175
./configure $INFER_CONFIGURE_OPTS
164176

configure.ac

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ AC_ARG_ENABLE(java-analyzers,
6767
BUILD_JAVA_ANALYZERS=$enable_java_analyzers
6868
AC_SUBST([BUILD_JAVA_ANALYZERS])
6969

70+
AC_ARG_ENABLE(go-analyzers,
71+
AS_HELP_STRING([--disable-go-analyzers],
72+
[do not build the Go analyzers (default is to build them)]),
73+
,
74+
enable_go_analyzers=yes)
75+
76+
BUILD_GO_ANALYZERS=$enable_go_analyzers
77+
AC_SUBST([BUILD_GO_ANALYZERS])
78+
7079
AC_ARG_WITH(fcp-clang,
7180
AS_HELP_STRING([--with-fcp-clang],
7281
[use $CLANG_PREFIX/bin/clang to override the default compiler (default is not to override)]),

infer/lib/go/src_to_ast_json.go

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"go/ast"
6+
"go/parser"
7+
"go/token"
8+
"log"
9+
"os"
10+
"strconv"
11+
"strings"
12+
)
13+
14+
const indInc = 2
15+
16+
func main() {
17+
args := os.Args
18+
if len(args) != 3 {
19+
fmt.Println("USAGE: " + args[0] + " file_name")
20+
os.Exit(0)
21+
}
22+
fset := token.NewFileSet()
23+
node, err := parser.ParseFile(fset, args[2], nil, parser.ParseComments)
24+
if err != nil {
25+
log.Fatal(err)
26+
}
27+
json_print(node, *fset, 0)
28+
29+
}
30+
31+
func pad(ind int) string {
32+
return strings.Repeat(" ", ind)
33+
}
34+
35+
func ident_obj(id ast.Ident, fset token.FileSet) string {
36+
pos := fset.PositionFor(id.NamePos, true)
37+
return "{\"Ln\":" + strconv.Itoa(pos.Line) + ", \"Col\":" + strconv.Itoa(pos.Column) + ", \"Id\":\"" + id.Name + "\"}"
38+
}
39+
40+
func json_print(node ast.Node, fset token.FileSet, ind int) {
41+
switch /*t := */ node.(type) {
42+
case *ast.File:
43+
fmt.Println("{")
44+
fmt.Println("\"Decls\":")
45+
fmt.Println("[")
46+
f, _ := node.(*ast.File)
47+
for i, d := range f.Decls {
48+
if i > 0 {
49+
fmt.Printf("%s,\n", pad(ind+indInc))
50+
}
51+
json_print(d, fset, ind+2*indInc)
52+
}
53+
fmt.Println("]")
54+
fmt.Println("}")
55+
case *ast.FuncDecl:
56+
fmt.Printf("%s[\n", pad(ind))
57+
fmt.Printf("%s\"FuncDecl\",\n", pad(ind+indInc))
58+
fmt.Printf("%s{\n", pad(ind+indInc))
59+
fd, _ := node.(*ast.FuncDecl)
60+
fmt.Printf("%s\"Name\":%s\n", pad(ind+2*indInc), ident_obj(*fd.Name, fset))
61+
fmt.Printf("%s,\n", pad(ind+2*indInc))
62+
json_print(fd.Type, fset, ind+2*indInc)
63+
fmt.Printf("%s,\n", pad(ind+2*indInc))
64+
fmt.Printf("%s\"Body\":\n", pad(ind+2*indInc))
65+
json_print(fd.Body, fset, ind+2*indInc)
66+
fmt.Printf("%s}\n", pad(ind+indInc))
67+
fmt.Printf("%s]\n", pad(ind))
68+
case *ast.Ident:
69+
id, _ := node.(*ast.Ident)
70+
fmt.Printf("%s[\"Ident\", %s]\n", pad(ind), ident_obj(*id, fset))
71+
case *ast.FuncType:
72+
fmt.Printf("%s\"FuncType\":\n", pad(ind))
73+
fmt.Printf("%s{\n", pad(ind))
74+
ft, _ := node.(*ast.FuncType)
75+
pos := fset.PositionFor(ft.Func, true)
76+
fmt.Printf("%s\"Ln\":%d, \"Col\":%d,\n",
77+
pad(ind+indInc), pos.Line, pos.Column)
78+
fmt.Printf("%s\"Params\":\n", pad(ind+indInc))
79+
json_print(ft.Params, fset, ind+indInc)
80+
fmt.Printf("%s,\n", pad(ind+indInc))
81+
fmt.Printf("%s\"Results\":\n", pad(ind+indInc))
82+
json_print(ft.Results, fset, ind+indInc)
83+
fmt.Printf("%s}\n", pad(ind))
84+
case *ast.FieldList:
85+
fmt.Printf("%s[\n", pad(ind))
86+
fl, _ := node.(*ast.FieldList)
87+
for i, f := range fl.List {
88+
if i > 0 {
89+
fmt.Printf("%s,\n", pad(ind+indInc))
90+
}
91+
json_print(f, fset, ind+2*indInc)
92+
}
93+
fmt.Printf("%s]\n", pad(ind))
94+
case *ast.Field:
95+
fmt.Printf("%s{\n", pad(ind))
96+
fmt.Printf("%s\"Names\":\n", pad(ind+indInc))
97+
fmt.Printf("%s[\n", pad(ind+indInc))
98+
f, _ := node.(*ast.Field)
99+
for i, n := range f.Names {
100+
if i > 0 {
101+
fmt.Printf("%s,\n", pad(ind+2*indInc))
102+
}
103+
fmt.Printf("%s%s\n", pad(ind+2*indInc), ident_obj(*n, fset))
104+
}
105+
fmt.Printf("%s]\n", pad(ind+indInc))
106+
fmt.Printf("%s,\n", pad(ind+indInc))
107+
fmt.Printf("%s\"Type\":\n", pad(ind+indInc))
108+
json_print(f.Type, fset, ind+2*indInc)
109+
fmt.Printf("%s}\n", pad(ind))
110+
case *ast.StarExpr:
111+
fmt.Printf("%s[\n", pad(ind))
112+
fmt.Printf("%s\"StarExpr\",\n", pad(ind+indInc))
113+
se, _ := node.(*ast.StarExpr)
114+
fmt.Printf("%s{\n", pad(ind+2*indInc))
115+
pos := fset.PositionFor(se.Star, true)
116+
fmt.Printf("%s\"Ln\":%d, \"Col\":%d,\n",
117+
pad(ind+3*indInc), pos.Line, pos.Column)
118+
fmt.Printf("%s\"X\":\n", pad(ind+3*indInc))
119+
json_print(se.X, fset, ind+4*indInc)
120+
fmt.Printf("%s}\n", pad(ind+2*indInc))
121+
fmt.Printf("%s]\n", pad(ind))
122+
case *ast.UnaryExpr:
123+
fmt.Printf("%s[\n", pad(ind))
124+
fmt.Printf("%s\"UnaryExpr\",\n", pad(ind+indInc))
125+
ue, _ := node.(*ast.UnaryExpr)
126+
fmt.Printf("%s{\n", pad(ind+2*indInc))
127+
pos := fset.PositionFor(ue.OpPos, true)
128+
fmt.Printf("%s\"Ln\":%d, \"Col\":%d, \"Tok\":\"%s\",\n",
129+
pad(ind+3*indInc), pos.Line, pos.Column, ue.Op.String())
130+
fmt.Printf("%s\"X\":\n", pad(ind+3*indInc))
131+
json_print(ue.X, fset, ind+4*indInc)
132+
fmt.Printf("%s}\n", pad(ind+2*indInc))
133+
fmt.Printf("%s]\n", pad(ind))
134+
case *ast.BlockStmt:
135+
fmt.Printf("%s{\n", pad(ind))
136+
bs, _ := node.(*ast.BlockStmt)
137+
lpos := fset.PositionFor(bs.Lbrace, true)
138+
fmt.Printf("%s\"LBrace\":{\"Ln\":%d, \"Col\":%d},\n",
139+
pad(ind+indInc), lpos.Line, lpos.Column)
140+
rpos := fset.PositionFor(bs.Rbrace, true)
141+
fmt.Printf("%s\"RBrace\":{\"Ln\":%d, \"Col\":%d},\n",
142+
pad(ind+indInc), rpos.Line, rpos.Column)
143+
fmt.Printf("%s\"StmtList\":\n", pad(ind+indInc))
144+
fmt.Printf("%s[\n", pad(ind+indInc))
145+
for i, s := range bs.List {
146+
if i > 0 {
147+
fmt.Printf("%s,\n", pad(ind+2*indInc))
148+
}
149+
json_print(s, fset, ind+2*indInc)
150+
}
151+
fmt.Printf("%s]\n", pad(ind+indInc))
152+
fmt.Printf("%s}\n", pad(ind))
153+
case *ast.ReturnStmt:
154+
fmt.Printf("%s[\n", pad(ind))
155+
fmt.Printf("%s\"ReturnStmt\",\n", pad(ind+indInc))
156+
fmt.Printf("%s{\n", pad(ind+indInc))
157+
rs, _ := node.(*ast.ReturnStmt)
158+
pos := fset.PositionFor(rs.Return, true)
159+
fmt.Printf("%s\"Ln\":%d, \"Col\":%d,\n",
160+
pad(ind+2*indInc), pos.Line, pos.Column)
161+
fmt.Printf("%s\"Results\":\n", pad(ind+2*indInc))
162+
fmt.Printf("%s[\n", pad(ind+2*indInc))
163+
for i, e := range rs.Results {
164+
if i > 0 {
165+
fmt.Printf("%s,\n", pad(ind+3*indInc))
166+
}
167+
json_print(e, fset, ind+3*indInc)
168+
}
169+
fmt.Printf("%s]\n", pad(ind+2*indInc))
170+
fmt.Printf("%s}\n", pad(ind+indInc))
171+
fmt.Printf("%s]\n", pad(ind))
172+
case *ast.CallExpr:
173+
fmt.Printf("%s\"CallExpr\":\n", pad(ind))
174+
fmt.Printf("%s{\n", pad(ind))
175+
c, _ := node.(*ast.CallExpr)
176+
json_print(c.Fun, fset, ind+indInc)
177+
fmt.Printf("%s,\n", pad(ind+indInc))
178+
fmt.Printf("%s\"Args\":\n", pad(ind+indInc))
179+
fmt.Printf("%s[\n", pad(ind+indInc))
180+
for i, e := range c.Args {
181+
if i > 0 {
182+
fmt.Printf("%s,\n", pad(ind+2*indInc))
183+
}
184+
fmt.Printf("%s{\n", pad(ind+2*indInc))
185+
json_print(e, fset, ind+3*indInc)
186+
fmt.Printf("%s}\n", pad(ind+2*indInc))
187+
}
188+
fmt.Printf("%s]\n", pad(ind+indInc))
189+
fmt.Printf("%s}\n", pad(ind))
190+
case *ast.BasicLit:
191+
bl, _ := node.(*ast.BasicLit)
192+
pos := fset.PositionFor(bl.ValuePos, true)
193+
fmt.Printf("%s[\"BasicLit\",{\"Ln\":%d, \"Col\":%d, \"Kind\":\"%s\", \"Value\":\"%s\"}]\n",
194+
pad(ind), pos.Line, pos.Column, bl.Kind.String(), bl.Value)
195+
case *ast.AssignStmt:
196+
fmt.Printf("%s[\n", pad(ind))
197+
fmt.Printf("%s\"AssignStmt\",\n", pad(ind+indInc))
198+
fmt.Printf("%s{\n", pad(ind+indInc))
199+
as, _ := node.(*ast.AssignStmt)
200+
pos := fset.PositionFor(as.TokPos, true)
201+
fmt.Printf("%s\"Ln\":%d, \"Col\":%d,\n",
202+
pad(ind+2*indInc), pos.Line, pos.Column)
203+
fmt.Printf("%s\"Lhs\":\n", pad(ind+2*indInc))
204+
fmt.Printf("%s[\n", pad(ind*2+indInc))
205+
for i, e := range as.Lhs {
206+
if i > 0 {
207+
fmt.Printf("%s,\n", pad(ind+3*indInc))
208+
}
209+
json_print(e, fset, ind+3*indInc)
210+
}
211+
fmt.Printf("%s]\n", pad(ind+2*indInc))
212+
fmt.Printf("%s,\n", pad(ind+2*indInc))
213+
fmt.Printf("%s\"Rhs\":\n", pad(ind+2*indInc))
214+
fmt.Printf("%s[\n", pad(ind*2+indInc))
215+
for i, e := range as.Rhs {
216+
if i > 0 {
217+
fmt.Printf("%s,\n", pad(ind+3*indInc))
218+
}
219+
json_print(e, fset, ind+3*indInc)
220+
}
221+
fmt.Printf("%s]\n", pad(ind+2*indInc))
222+
fmt.Printf("%s}\n", pad(ind+indInc))
223+
fmt.Printf("%s]\n", pad(ind))
224+
case *ast.DeclStmt:
225+
fmt.Printf("%s[\n", pad(ind))
226+
fmt.Printf("%s\"DeclStmt\",\n", pad(ind+indInc))
227+
fmt.Printf("%s{\n", pad(ind+indInc))
228+
ds, _ := node.(*ast.DeclStmt)
229+
fmt.Printf("%s\"Decl\":\n", pad(ind+2*indInc))
230+
json_print(ds.Decl, fset, ind+2*indInc)
231+
fmt.Printf("%s}\n", pad(ind+indInc))
232+
fmt.Printf("%s]\n", pad(ind))
233+
case *ast.GenDecl:
234+
fmt.Printf("%s[\n", pad(ind))
235+
fmt.Printf("%s\"GenDecl\",\n", pad(ind+indInc))
236+
fmt.Printf("%s{\n", pad(ind+indInc))
237+
gd, _ := node.(*ast.GenDecl)
238+
pos := fset.PositionFor(gd.TokPos, true)
239+
fmt.Printf("%s\"Ln\":%d, \"Col\":%d, \"Tok\":\"%s\",\n",
240+
pad(ind+2*indInc), pos.Line, pos.Column, gd.Tok.String())
241+
fmt.Printf("%s\"Specs\":\n", pad(ind+2*indInc))
242+
fmt.Printf("%s[\n", pad(ind+2*indInc))
243+
for i, s := range gd.Specs {
244+
if i > 0 {
245+
fmt.Printf("%s,\n", pad(ind+3*indInc))
246+
}
247+
json_print(s, fset, ind+3*indInc)
248+
}
249+
fmt.Printf("%s]\n", pad(ind+2*indInc))
250+
fmt.Printf("%s}\n", pad(ind+indInc))
251+
fmt.Printf("%s]\n", pad(ind))
252+
case *ast.ValueSpec:
253+
fmt.Printf("%s[\n", pad(ind))
254+
fmt.Printf("%s\"ValueSpec\",\n", pad(ind+indInc))
255+
fmt.Printf("%s{\n", pad(ind+indInc))
256+
vs, _ := node.(*ast.ValueSpec)
257+
fmt.Printf("%s\"Type\":\n", pad(ind+2*indInc))
258+
json_print(vs.Type, fset, ind+2*indInc)
259+
fmt.Printf("%s,\n", pad(ind+2*indInc))
260+
fmt.Printf("%s\"Names\":\n", pad(ind+2*indInc))
261+
fmt.Printf("%s[\n", pad(ind+2*indInc))
262+
for i, n := range vs.Names {
263+
if i > 0 {
264+
fmt.Printf("%s,\n", pad(ind+3*indInc))
265+
}
266+
fmt.Printf("%s%s\n", pad(ind+3*indInc), ident_obj(*n, fset))
267+
}
268+
fmt.Printf("%s]\n", pad(ind+2*indInc))
269+
fmt.Printf("%s,\n", pad(ind+2*indInc))
270+
fmt.Printf("%s\"Values\":\n", pad(ind+2*indInc))
271+
fmt.Printf("%s[\n", pad(ind+2*indInc))
272+
for i, v := range vs.Values {
273+
if i > 0 {
274+
fmt.Printf("%s,\n", pad(ind+3*indInc))
275+
}
276+
json_print(v, fset, ind+3*indInc)
277+
}
278+
fmt.Printf("%s]\n", pad(ind+2*indInc))
279+
fmt.Printf("%s}\n", pad(ind+indInc))
280+
fmt.Printf("%s]\n", pad(ind))
281+
}
282+
283+
}

infer/man/man1/infer-capture.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ OPTIONS
5656

5757
--force-integration command
5858
Proceed as if the first argument after -- was command. Possible
59-
values: ant, buck, gradle, gradlew, java, javac, cc, clang, gcc,
60-
clang++, c++, g++, make, configure, cmake, waf, mvn, mvnw,
59+
values: ant, buck, gradle, gradlew, java, javac, go, cc, clang,
60+
gcc, clang++, c++, g++, make, configure, cmake, waf, mvn, mvnw,
6161
ndk-build, xcodebuild.
6262

6363
--help

infer/man/man1/infer-full.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,8 @@ OPTIONS
358358

359359
--force-integration command
360360
Proceed as if the first argument after -- was command. Possible
361-
values: ant, buck, gradle, gradlew, java, javac, cc, clang, gcc,
362-
clang++, c++, g++, make, configure, cmake, waf, mvn, mvnw,
361+
values: ant, buck, gradle, gradlew, java, javac, go, cc, clang,
362+
gcc, clang++, c++, g++, make, configure, cmake, waf, mvn, mvnw,
363363
ndk-build, xcodebuild. See also infer-capture(1) and infer-run(1).
364364

365365
--no-fragment-retains-view

infer/man/man1/infer-run.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ OPTIONS
6969

7070
--force-integration command
7171
Proceed as if the first argument after -- was command. Possible
72-
values: ant, buck, gradle, gradlew, java, javac, cc, clang, gcc,
73-
clang++, c++, g++, make, configure, cmake, waf, mvn, mvnw,
72+
values: ant, buck, gradle, gradlew, java, javac, go, cc, clang,
73+
gcc, clang++, c++, g++, make, configure, cmake, waf, mvn, mvnw,
7474
ndk-build, xcodebuild.
7575

7676
--help

0 commit comments

Comments
 (0)