diff options
Diffstat (limited to 'src/cmd')
76 files changed, 1392 insertions, 308 deletions
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h index 549e0c88a..ff6d51916 100644 --- a/src/cmd/5c/gc.h +++ b/src/cmd/5c/gc.h @@ -28,7 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. - +#include <u.h> #include "../cc/cc.h" #include "../5l/5.out.h" diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 4afed2b80..2c9e50d00 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -68,9 +68,6 @@ enum { ElfStrText, ElfStrData, ElfStrBss, - ElfStrGosymcounts, - ElfStrGosymtab, - ElfStrGopclntab, ElfStrSymtab, ElfStrStrtab, ElfStrShstrtab, @@ -160,12 +157,11 @@ doelf(void) elfstr[ElfStrEmpty] = addstring(shstrtab, ""); elfstr[ElfStrText] = addstring(shstrtab, ".text"); elfstr[ElfStrData] = addstring(shstrtab, ".data"); - addstring(shstrtab, ".rodata"); elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); + addstring(shstrtab, ".rodata"); + addstring(shstrtab, ".gosymtab"); + addstring(shstrtab, ".gopclntab"); if(!debug['s']) { - elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts"); - elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab"); - elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab"); elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab"); elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab"); } @@ -307,10 +303,11 @@ asmb(void) seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); codeblk(sect->vaddr, sect->len); - /* output read-only data in text segment */ - sect = segtext.sect->next; - seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); - datblk(sect->vaddr, sect->len); + /* output read-only data in text segment (rodata, gosymtab and pclntab) */ + for(sect = sect->next; sect != nil; sect = sect->next) { + seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); + datblk(sect->vaddr, sect->len); + } if(debug['v']) Bprint(&bso, "%5.2f datblk\n", cputime()); @@ -572,18 +569,6 @@ asmb(void) elfshbits(sect); if (!debug['s']) { - sh = newElfShdr(elfstr[ElfStrGosymtab]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - shsym(sh, lookup("symtab", 0)); - - sh = newElfShdr(elfstr[ElfStrGopclntab]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - shsym(sh, lookup("pclntab", 0)); - sh = newElfShdr(elfstr[ElfStrSymtab]); sh->type = SHT_SYMTAB; sh->off = symo; diff --git a/src/cmd/5l/mkenam b/src/cmd/5l/mkenam index 265cb9988..6cccb0263 100644 --- a/src/cmd/5l/mkenam +++ b/src/cmd/5l/mkenam @@ -28,18 +28,18 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -ed - ../5l/5.out.h <<'!' -v/^ A/d -,s/^ A/ "/ -g/ .*$/s/// -,s/,*$/",/ -1i -char* anames[] = -{ -. -$a -}; -. -w enam.c -Q -! +awk ' +BEGIN { + print "char* anames[] =" + print "{" +} + +/^ A/ { + name=$1 + sub(/,/, "", name) + sub(/^A/, "", name) + print "\t\"" name "\"," +} + +END { print "};" } +' ../5l/5.out.h >enam.c diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h index 735cd8909..775d97281 100644 --- a/src/cmd/6c/gc.h +++ b/src/cmd/6c/gc.h @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "../cc/cc.h" #include "../6l/6.out.h" diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index 4c04112b7..9136e0379 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -87,9 +87,6 @@ enum { ElfStrText, ElfStrData, ElfStrBss, - ElfStrGosymcounts, - ElfStrGosymtab, - ElfStrGopclntab, ElfStrShstrtab, ElfStrSymtab, ElfStrStrtab, @@ -571,10 +568,9 @@ doelf(void) elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); addstring(shstrtab, ".elfdata"); addstring(shstrtab, ".rodata"); + addstring(shstrtab, ".gosymtab"); + addstring(shstrtab, ".gopclntab"); if(!debug['s']) { - elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts"); - elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab"); - elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab"); elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab"); elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab"); dwarfaddshstrings(shstrtab); @@ -718,10 +714,11 @@ asmb(void) seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); codeblk(sect->vaddr, sect->len); - /* output read-only data in text segment */ - sect = segtext.sect->next; - seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); - datblk(sect->vaddr, sect->len); + /* output read-only data in text segment (rodata, gosymtab and pclntab) */ + for(sect = sect->next; sect != nil; sect = sect->next) { + seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); + datblk(sect->vaddr, sect->len); + } if(debug['v']) Bprint(&bso, "%5.2f datblk\n", cputime()); @@ -1013,18 +1010,6 @@ asmb(void) elfshbits(sect); if (!debug['s']) { - sh = newElfShdr(elfstr[ElfStrGosymtab]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - shsym(sh, lookup("symtab", 0)); - - sh = newElfShdr(elfstr[ElfStrGopclntab]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - shsym(sh, lookup("pclntab", 0)); - sh = newElfShdr(elfstr[ElfStrSymtab]); sh->type = SHT_SYMTAB; sh->off = symo; diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam index 5cabb2633..3001dbe93 100644 --- a/src/cmd/6l/mkenam +++ b/src/cmd/6l/mkenam @@ -28,18 +28,18 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -/bin/ed - ../6l/6.out.h <<'!' -v/^ A/d -,s/^ A/ "/ -g/ .*$/s/// -,s/,*$/",/ -1i -char* anames[] = -{ -. -$a -}; -. -w enam.c -Q -! +awk ' +BEGIN { + print "char* anames[] =" + print "{" +} + +/^ A/ { + name=$1 + sub(/,/, "", name) + sub(/^A/, "", name) + print "\t\"" name "\"," +} + +END { print "};" } +' ../6l/6.out.h >enam.c diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h index 3cb30f4c2..c5c22d7ba 100644 --- a/src/cmd/8a/a.h +++ b/src/cmd/8a/a.h @@ -28,8 +28,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include <u.h> -#include <libc.h> #include <bio.h> #include "../8l/8.out.h" @@ -57,7 +55,9 @@ typedef struct Gen2 Gen2; #define NSYMB 500 #define BUFSIZ 8192 #define HISTSZ 20 +#ifndef EOF #define EOF (-1) +#endif #define IGN (-2) #define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) #define NHASH 503 diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y index 04662f83d..a8ac773da 100644 --- a/src/cmd/8a/a.y +++ b/src/cmd/8a/a.y @@ -29,7 +29,9 @@ // THE SOFTWARE. %{ +#include <u.h> #include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */ +#include <libc.h> #include "a.h" %} %union { diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c index 078861877..ab4de417a 100644 --- a/src/cmd/8a/lex.c +++ b/src/cmd/8a/lex.c @@ -29,9 +29,10 @@ // THE SOFTWARE. #define EXTERN +#include <u.h> +#include <libc.h> #include "a.h" #include "y.tab.h" -#include <ctype.h> enum { diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h index 9fead60e4..32b80e995 100644 --- a/src/cmd/8c/gc.h +++ b/src/cmd/8c/gc.h @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "../cc/cc.h" #include "../8l/8.out.h" @@ -400,6 +401,7 @@ void shiftit(Type*, Node*, Node*); #pragma varargck type "A" int #pragma varargck type "B" Bits #pragma varargck type "D" Adr* +#pragma varargck type "lD" Adr* #pragma varargck type "P" Prog* #pragma varargck type "R" int #pragma varargck type "S" char* diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c index d07a5439c..769ef2c66 100644 --- a/src/cmd/8c/swt.c +++ b/src/cmd/8c/swt.c @@ -237,10 +237,10 @@ outcode(void) Bprint(&b, "\n"); Bprint(&b, "$$ // exports\n\n"); Bprint(&b, "$$ // local types\n\n"); - Bprint(&b, "$$ // dynimport\n", thestring); + Bprint(&b, "$$ // dynimport\n"); for(i=0; i<ndynimp; i++) Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path); - Bprint(&b, "\n$$ // dynexport\n", thestring); + Bprint(&b, "\n$$ // dynexport\n"); for(i=0; i<ndynexp; i++) Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote); Bprint(&b, "\n$$\n\n"); diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index a9a720af1..e1ccfb8a3 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -83,9 +83,6 @@ enum { ElfStrText, ElfStrData, ElfStrBss, - ElfStrGosymcounts, - ElfStrGosymtab, - ElfStrGopclntab, ElfStrShstrtab, ElfStrSymtab, ElfStrStrtab, @@ -531,10 +528,9 @@ doelf(void) elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); addstring(shstrtab, ".elfdata"); addstring(shstrtab, ".rodata"); + addstring(shstrtab, ".gosymtab"); + addstring(shstrtab, ".gopclntab"); if(!debug['s']) { - elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts"); - elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab"); - elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab"); elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab"); elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab"); dwarfaddshstrings(shstrtab); @@ -679,10 +675,11 @@ asmb(void) seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); codeblk(sect->vaddr, sect->len); - /* output read-only data in text segment */ - sect = segtext.sect->next; - seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); - datblk(sect->vaddr, sect->len); + /* output read-only data in text segment (rodata, gosymtab and pclntab) */ + for(sect = sect->next; sect != nil; sect = sect->next) { + seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0); + datblk(sect->vaddr, sect->len); + } if(debug['v']) Bprint(&bso, "%5.2f datblk\n", cputime()); @@ -1083,18 +1080,6 @@ asmb(void) elfshbits(sect); if (!debug['s']) { - sh = newElfShdr(elfstr[ElfStrGosymtab]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - shsym(sh, lookup("symtab", 0)); - - sh = newElfShdr(elfstr[ElfStrGopclntab]); - sh->type = SHT_PROGBITS; - sh->flags = SHF_ALLOC; - sh->addralign = 1; - shsym(sh, lookup("pclntab", 0)); - sh = newElfShdr(elfstr[ElfStrSymtab]); sh->type = SHT_SYMTAB; sh->off = symo; diff --git a/src/cmd/8l/mkenam b/src/cmd/8l/mkenam index b33fec7cc..992aa3160 100644 --- a/src/cmd/8l/mkenam +++ b/src/cmd/8l/mkenam @@ -28,18 +28,18 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -ed - ../8l/8.out.h <<'!' -v/^ A/d -,s/^ A/ "/ -g/ .*$/s/// -,s/,*$/",/ -1i -char* anames[] = -{ -. -$a -}; -. -w enam.c -Q -! +awk ' +BEGIN { + print "char* anames[] =" + print "{" +} + +/^ A/ { + name=$1 + sub(/,/, "", name) + sub(/^A/, "", name) + print "\t\"" name "\"," +} + +END { print "};" } +' ../8l/8.out.h >enam.c diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c index c6a6722bd..23147e519 100644 --- a/src/cmd/cc/acid.c +++ b/src/cmd/cc/acid.c @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" static char *kwd[] = diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c index aef4449e8..4496d65e7 100644 --- a/src/cmd/cc/bits.c +++ b/src/cmd/cc/bits.c @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" Bits diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h index 8e8f6af44..a38e658ce 100644 --- a/src/cmd/cc/cc.h +++ b/src/cmd/cc/cc.h @@ -28,10 +28,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include <u.h> #include <libc.h> #include <bio.h> -#include <ctype.h> #pragma lib "../cc/cc.a$O" @@ -816,7 +814,9 @@ int machcap(Node*); #pragma varargck type "L" int32 #pragma varargck type "Q" int32 #pragma varargck type "O" int +#pragma varargck type "O" uint #pragma varargck type "T" Type* +#pragma varargck type "U" char* #pragma varargck type "|" int enum diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y index 470fdae26..515a80372 100644 --- a/src/cmd/cc/cc.y +++ b/src/cmd/cc/cc.y @@ -29,6 +29,7 @@ // THE SOFTWARE. %{ +#include <u.h> #include <stdio.h> /* if we don't, bison will, and cc.h re-#defines getc */ #include "cc.h" %} diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c index b1a8a4704..6e470ee64 100644 --- a/src/cmd/cc/com.c +++ b/src/cmd/cc/com.c @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" int compar(Node*, int); @@ -127,7 +128,7 @@ tcomo(Node *n, int f) case ORETURN: if(l == Z) { if(n->type->etype != TVOID) - warn(n, "null return of a typed function"); + diag(n, "null return of a typed function"); break; } if(tcom(l)) diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c index 8d6e07d1b..fb7a3f750 100644 --- a/src/cmd/cc/com64.c +++ b/src/cmd/cc/com64.c @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" /* diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c index 6f1b8a9a9..d624bf247 100644 --- a/src/cmd/cc/dcl.c +++ b/src/cmd/cc/dcl.c @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" Node* diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c index 0e51101f1..42c245b56 100644 --- a/src/cmd/cc/dpchk.c +++ b/src/cmd/cc/dpchk.c @@ -28,6 +28,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> +#include <ctype.h> #include "cc.h" #include "y.tab.h" @@ -56,7 +58,9 @@ struct Tname { char* name; int param; + int count; Tname* link; + Tprot* prot; }; static Type* indchar; @@ -131,8 +135,8 @@ getflag(char *s) return flag; } -void -newprot(Sym *m, Type *t, char *s) +static void +newprot(Sym *m, Type *t, char *s, Tprot **prot) { Bits flag; Tprot *l; @@ -142,32 +146,37 @@ newprot(Sym *m, Type *t, char *s) return; } flag = getflag(s); - for(l=tprot; l; l=l->link) + for(l=*prot; l; l=l->link) if(beq(flag, l->flag) && sametype(t, l->type)) return; l = alloc(sizeof(*l)); l->type = t; l->flag = flag; - l->link = tprot; - tprot = l; + l->link = *prot; + *prot = l; } -void -newname(char *s, int p) +static Tname* +newname(char *s, int p, int count) { Tname *l; for(l=tname; l; l=l->link) if(strcmp(l->name, s) == 0) { - if(l->param != p) + if(p >= 0 && l->param != p) yyerror("vargck %s already defined\n", s); - return; + return l; } + if(p < 0) + return nil; + l = alloc(sizeof(*l)); l->name = s; l->param = p; l->link = tname; + l->count = count; tname = l; + return l; } void @@ -234,6 +243,7 @@ pragvararg(void) int n, c; char *t; Type *ty; + Tname *l; if(!debug['F']) goto out; @@ -244,6 +254,8 @@ pragvararg(void) goto cktype; if(s && strcmp(s->name, "flag") == 0) goto ckflag; + if(s && strcmp(s->name, "countpos") == 0) + goto ckcount; yyerror("syntax in #pragma varargck"); goto out; @@ -255,7 +267,18 @@ ckpos: n = getnsn(); if(n < 0) goto bad; - newname(s->name, n); + newname(s->name, n, 0); + goto out; + +ckcount: +/*#pragma varargck countpos name 2*/ + s = getsym(); + if(s == S) + goto bad; + n = getnsn(); + if(n < 0) + goto bad; + newname(s->name, 0, n); goto out; ckflag: @@ -276,6 +299,25 @@ ckflag: goto out; cktype: + c = getnsc(); + unget(c); + if(c != '"') { +/*#pragma varargck type name int*/ + s = getsym(); + if(s == S) + goto bad; + l = newname(s->name, -1, -1); + s = getsym(); + if(s == S) + goto bad; + ty = s->type; + while((c = getnsc()) == '*') + ty = typ(TIND, ty); + unget(c); + newprot(s, ty, "a", &l->prot); + goto out; + } + /*#pragma varargck type O int*/ t = getquoted(); if(t == nil) @@ -287,7 +329,7 @@ cktype: while((c = getnsc()) == '*') ty = typ(TIND, ty); unget(c); - newprot(s, ty, t); + newprot(s, ty, t, &tprot); goto out; bad: @@ -384,7 +426,8 @@ dpcheck(Node *n) char *s; Node *a, *b; Tname *l; - int i; + Tprot *tl; + int i, j; if(n == Z) return; @@ -398,20 +441,76 @@ dpcheck(Node *n) if(l == 0) return; + if(l->count > 0) { + // fetch count, then check remaining length + i = l->count; + a = nil; + b = n->right; + while(i > 0) { + b = nextarg(b, &a); + i--; + } + if(a == Z) { + diag(n, "can't find count arg"); + return; + } + if(a->op != OCONST || !typechl[a->type->etype]) { + diag(n, "count is invalid constant"); + return; + } + j = a->vconst; + i = 0; + while(b != Z) { + b = nextarg(b, &a); + i++; + } + if(i != j) + diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j); + } + + if(l->prot != nil) { + // check that all arguments after param or count + // are listed in type list. + i = l->count; + if(i == 0) + i = l->param; + if(i == 0) + return; + a = nil; + b = n->right; + while(i > 0) { + b = nextarg(b, &a); + i--; + } + if(a == Z) { + diag(n, "can't find count/param arg"); + return; + } + while(b != Z) { + b = nextarg(b, &a); + for(tl=l->prot; tl; tl=tl->link) + if(sametype(a->type, tl->type)) + break; + if(tl == nil) + diag(a, "invalid type %T in call to %s", a->type, s); + } + } + + if(l->param <= 0) + return; i = l->param; a = nil; b = n->right; - a = Z; while(i > 0) { b = nextarg(b, &a); i--; } if(a == Z) { - warn(n, "cant find format arg"); + diag(n, "can't find format arg"); return; } if(!sametype(indchar, a->type)) { - warn(n, "format arg type %T", a->type); + diag(n, "format arg type %T", a->type); return; } if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) { diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c index 21d86258f..99477b2b2 100644 --- a/src/cmd/cc/funct.c +++ b/src/cmd/cc/funct.c @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" typedef struct Ftab Ftab; diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c index 9503cb2f2..3ba979c8a 100644 --- a/src/cmd/cc/godefs.c +++ b/src/cmd/cc/godefs.c @@ -29,6 +29,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" static int upper; @@ -238,7 +239,7 @@ printtypename(Type *t) Bprint(&outbuf, "%U", n); break; case TFUNC: - Bprint(&outbuf, "func(", t); + Bprint(&outbuf, "func("); for(t1 = t->down; t1 != T; t1 = t1->down) { if(t1->etype == TVOID) break; diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c index 71cc89bf0..15f2d374d 100644 --- a/src/cmd/cc/lex.c +++ b/src/cmd/cc/lex.c @@ -28,6 +28,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> +#include <ctype.h> #include "cc.h" #include "y.tab.h" @@ -384,7 +386,7 @@ lookup(void) }else *w++ = *r; } - *w++ = '\0'; + *w = '\0'; h = 0; for(p=symb; *p;) { @@ -1524,7 +1526,7 @@ alloc(int32 n) p = malloc(n); if(p == nil) { print("alloc out of mem\n"); - exit(1); + exits("alloc: out of mem"); } memset(p, 0, n); return p; @@ -1538,7 +1540,7 @@ allocn(void *p, int32 n, int32 d) p = realloc(p, n+d); if(p == nil) { print("allocn out of mem\n"); - exit(1); + exits("allocn: out of mem"); } if(d > 0) memset((char*)p+n, 0, d); diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody index 24f9bdc85..f4cc19c2e 100644 --- a/src/cmd/cc/lexbody +++ b/src/cmd/cc/lexbody @@ -96,7 +96,7 @@ alloc(int32 n) p = malloc(n); if(p == nil) { print("alloc out of mem\n"); - exit(1); + exits("alloc: out of mem"); } memset(p, 0, n); return p; @@ -110,7 +110,7 @@ allocn(void *p, int32 n, int32 d) p = realloc(p, n+d); if(p == nil) { print("allocn out of mem\n"); - exit(1); + exits("allocn: out of mem"); } if(d > 0) memset((char*)p+n, 0, d); @@ -245,7 +245,7 @@ lookup(void) }else *w++ = *r; } - *w++ = '\0'; + *w = '\0'; h = 0; for(p=symb; c = *p; p++) diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c index c08cd9c97..43ae214d7 100644 --- a/src/cmd/cc/mac.c +++ b/src/cmd/cc/mac.c @@ -28,6 +28,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> +#include <ctype.h> #include "cc.h" #include "macbody" diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody index ca8a54c0b..ed66361f1 100644 --- a/src/cmd/cc/macbody +++ b/src/cmd/cc/macbody @@ -830,11 +830,11 @@ linehist(char *f, int offset) if(debug['f']) if(f) { if(offset) - print("%4ld: %s (#line %d)\n", lineno, f, offset); + print("%4d: %s (#line %d)\n", lineno, f, offset); else - print("%4ld: %s\n", lineno, f); + print("%4d: %s\n", lineno, f); } else - print("%4ld: <pop>\n", lineno); + print("%4d: <pop>\n", lineno); newflag = 0; h = alloc(sizeof(Hist)); diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c index ec5aa86e9..f8fc1d88b 100644 --- a/src/cmd/cc/omachcap.c +++ b/src/cmd/cc/omachcap.c @@ -28,11 +28,13 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" /* default, like old cc */ int machcap(Node *n) { + USED(n); return 0; } diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index 5d17cafc9..0e5e8c059 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -112,7 +112,7 @@ codgen(Node *n, Node *nn) warnreach = 1; gen(n); if(canreach && thisfn->link->etype != TVOID) - warn(Z, "no return at end of function: %s", n1->sym->name); + diag(Z, "no return at end of function: %s", n1->sym->name); noretval(3); gbranch(ORETURN); diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c index 3047ca44f..193331f77 100644 --- a/src/cmd/cc/scon.c +++ b/src/cmd/cc/scon.c @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" static Node* diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c index e0d5df719..e5992e213 100644 --- a/src/cmd/cc/sub.c +++ b/src/cmd/cc/sub.c @@ -28,6 +28,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> #include "cc.h" Node* diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 6b930f151..a4d83f1e7 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -66,7 +66,7 @@ func cname(s string) string { // preamble. Multiple occurrences are concatenated with a separating space, // even across files. func (p *Package) ParseFlags(f *File, srcfile string) { - linesIn := strings.Split(f.Preamble, "\n", -1) + linesIn := strings.Split(f.Preamble, "\n") linesOut := make([]string, 0, len(linesIn)) NextLine: @@ -78,7 +78,7 @@ NextLine: } l = strings.TrimSpace(l[4:]) - fields := strings.Split(l, ":", 2) + fields := strings.SplitN(l, ":", 2) if len(fields) != 2 { fatalf("%s: bad #cgo line: %s", srcfile, line) } @@ -275,7 +275,7 @@ func (p *Package) loadDefines(f *File) { b.WriteString(f.Preamble) stdout := p.gccDefines(b.Bytes()) - for _, line := range strings.Split(stdout, "\n", -1) { + for _, line := range strings.Split(stdout, "\n") { if len(line) < 9 || line[0:7] != "#define" { continue } @@ -397,7 +397,7 @@ func (p *Package) guessKinds(f *File) []*Name { isConst[i] = true // until proven otherwise } - for _, line := range strings.Split(stderr, "\n", -1) { + for _, line := range strings.Split(stderr, "\n") { if len(line) < 9 || line[0:9] != "cgo-test:" { // the user will see any compiler errors when the code is compiled later. continue @@ -1188,7 +1188,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { if ss, ok := dwarfToName[s]; ok { s = ss } - s = strings.Join(strings.Split(s, " ", -1), "") // strip spaces + s = strings.Join(strings.Split(s, " "), "") // strip spaces name := c.Ident("_Ctype_" + s) typedef[name.Name] = t.Go t.Go = name diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 7eecb3437..6802dd1cf 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -148,7 +148,7 @@ func dynimport(obj string) { fatalf("cannot load imported symbols from PE file %s: %v", obj, err) } for _, s := range sym { - ss := strings.Split(s, ":", -1) + ss := strings.Split(s, ":") fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1])) } return diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go index cac39179f..0b0443156 100644 --- a/src/cmd/ebnflint/ebnflint.go +++ b/src/cmd/ebnflint/ebnflint.go @@ -35,6 +35,12 @@ var ( ) +func report(err os.Error) { + scanner.PrintError(os.Stderr, err) + os.Exit(1) +} + + func extractEBNF(src []byte) []byte { var buf bytes.Buffer @@ -75,34 +81,35 @@ func extractEBNF(src []byte) []byte { func main() { flag.Parse() - var filename string + var ( + filename string + src []byte + err os.Error + ) switch flag.NArg() { case 0: - filename = "/dev/stdin" + filename = "<stdin>" + src, err = ioutil.ReadAll(os.Stdin) case 1: filename = flag.Arg(0) + src, err = ioutil.ReadFile(filename) default: usage() } - - src, err := ioutil.ReadFile(filename) if err != nil { - scanner.PrintError(os.Stderr, err) - os.Exit(1) + report(err) } - if filepath.Ext(filename) == ".html" { + if filepath.Ext(filename) == ".html" || bytes.Index(src, open) >= 0 { src = extractEBNF(src) } grammar, err := ebnf.Parse(fset, filename, src) if err != nil { - scanner.PrintError(os.Stderr, err) - os.Exit(1) + report(err) } if err = ebnf.Verify(fset, grammar, *start); err != nil { - scanner.PrintError(os.Stderr, err) - os.Exit(1) + report(err) } } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index b68768165..8ca086ee0 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -302,6 +302,7 @@ struct Sym uchar flags; uchar sym; // huffman encoding in object file Sym* link; + int32 npkg; // number of imported packages with this name // saved and restored by dcopy Pkg* pkg; @@ -777,6 +778,7 @@ EXTERN int32 nhunk; EXTERN int32 thunk; EXTERN int exporting; +EXTERN int erroring; EXTERN int noargnames; EXTERN int funcdepth; diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 5d28c0e3b..01a4e822f 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -237,7 +237,11 @@ import_here: import_package: LPACKAGE sym import_safety ';' { - importpkg->name = $2->name; + if(importpkg->name == nil) { + importpkg->name = $2->name; + pkglookup($2->name, nil)->npkg++; + } else if(strcmp(importpkg->name, $2->name) != 0) + yyerror("conflicting names %s and %s for package %Z", importpkg->name, $2->name, importpkg->path); importpkg->direct = 1; if(safemode && !curio.importsafe) @@ -1657,7 +1661,11 @@ hidden_import: Pkg *p; p = mkpkg($3.u.sval); - p->name = $2->name; + if(p->name == nil) { + p->name = $2->name; + pkglookup($2->name, nil)->npkg++; + } else if(strcmp(p->name, $2->name) != 0) + yyerror("conflicting names %s and %s for package %Z", p->name, $2->name, p->path); } | LVAR hidden_pkg_importsym hidden_type ';' { diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 8eb60de31..40b0c4fd1 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -45,10 +45,12 @@ adderr(int line, char *fmt, va_list arg) Fmt f; Error *p; + erroring++; fmtstrinit(&f); fmtprint(&f, "%L: ", line); fmtvprint(&f, fmt, arg); fmtprint(&f, "\n"); + erroring--; if(nerr >= merr) { if(merr == 0) @@ -1122,7 +1124,14 @@ Sconv(Fmt *fp) return 0; } - if(s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) { + if(s->pkg && s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) { + // This one is for the user. If the package name + // was used by multiple packages, give the full + // import path to disambiguate. + if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1) { + fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name); + return 0; + } fmtprint(fp, "%s.%s", s->pkg->name, s->name); return 0; } diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go index 54bebe854..50043e2ab 100644 --- a/src/cmd/godoc/codewalk.go +++ b/src/cmd/godoc/codewalk.go @@ -74,7 +74,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) { // A Codewalk represents a single codewalk read from an XML file. type Codewalk struct { - Title string "attr" + Title string `xml:"attr"` File []string Step []*Codestep } @@ -83,9 +83,9 @@ type Codewalk struct { // A Codestep is a single step in a codewalk. type Codestep struct { // Filled in from XML - Src string "attr" - Title string "attr" - XML string "innerxml" + Src string `xml:"attr"` + Title string `xml:"attr"` + XML string `xml:"innerxml"` // Derived from Src; not in XML. Err os.Error @@ -168,7 +168,7 @@ func loadCodewalk(filename string) (*Codewalk, os.Error) { cw.File[i] = f i++ } - sort.SortStrings(cw.File) + sort.Strings(cw.File) return cw, nil } diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go index af44fa16a..e98e93a46 100644 --- a/src/cmd/godoc/dirtrees.go +++ b/src/cmd/godoc/dirtrees.go @@ -30,7 +30,7 @@ type Directory struct { func isGoFile(fi FileInfo) bool { name := fi.Name() return fi.IsRegular() && - !strings.HasPrefix(name, ".") && // ignore .files + len(name) > 0 && name[0] != '.' && // ignore .files filepath.Ext(name) == ".go" } @@ -43,7 +43,8 @@ func isPkgFile(fi FileInfo) bool { func isPkgDir(fi FileInfo) bool { name := fi.Name() - return fi.IsDirectory() && len(name) > 0 && name[0] != '_' + return fi.IsDirectory() && len(name) > 0 && + name[0] != '_' && name[0] != '.' // ignore _files and .files } @@ -267,8 +268,8 @@ func (dir *Directory) lookupLocal(name string) *Directory { // lookup looks for the *Directory for a given path, relative to dir. func (dir *Directory) lookup(path string) *Directory { - d := strings.Split(dir.Path, string(filepath.Separator), -1) - p := strings.Split(path, string(filepath.Separator), -1) + d := strings.Split(dir.Path, string(filepath.Separator)) + p := strings.Split(path, string(filepath.Separator)) i := 0 for i < len(d) { if i >= len(p) || d[i] != p[i] { diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go index 6987d911b..20ebd3183 100644 --- a/src/cmd/godoc/godoc.go +++ b/src/cmd/godoc/godoc.go @@ -9,6 +9,7 @@ import ( "flag" "fmt" "go/ast" + "go/build" "go/doc" "go/printer" "go/token" @@ -83,8 +84,16 @@ var ( func initHandlers() { - fsMap.Init(*pkgPath) - fileServer = http.FileServer(*goroot, "") + paths := filepath.SplitList(*pkgPath) + for _, t := range build.Path { + if t.Goroot { + continue + } + paths = append(paths, t.SrcDir()) + } + fsMap.Init(paths) + + fileServer = http.FileServer(http.Dir(*goroot)) cmdHandler = httpHandler{"/cmd/", filepath.Join(*goroot, "src", "cmd"), false} pkgHandler = httpHandler{"/pkg/", filepath.Join(*goroot, "src", "pkg"), true} } @@ -160,7 +169,7 @@ func readDirList(filename string) ([]string, os.Error) { } return e == nil && isPkgDir(d) } - list := canonicalizePaths(strings.Split(string(contents), "\n", -1), filter) + list := canonicalizePaths(strings.Split(string(contents), "\n"), filter) // for each parent path, remove all it's children q // (requirement for binary search to work when filtering) i := 0 diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go index 61caee101..e0c89e794 100644 --- a/src/cmd/godoc/index.go +++ b/src/cmd/godoc/index.go @@ -901,7 +901,7 @@ func isIdentifier(s string) bool { // identifier, Lookup returns a LookupResult, and a list of alternative // spellings, if any. If the query syntax is wrong, an error is reported. func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, err os.Error) { - ss := strings.Split(query, ".", -1) + ss := strings.Split(query, ".") // check query syntax for _, s := range ss { @@ -954,7 +954,7 @@ func (list positionList) Swap(i, j int) { list[i], list[j] = list[j], list[ // unique returns the list sorted and with duplicate entries removed func unique(list []int) []int { - sort.SortInts(list) + sort.Ints(list) var last int i := 0 for _, x := range list { diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go index 55f6031bc..51fcf8dd0 100644 --- a/src/cmd/godoc/main.go +++ b/src/cmd/godoc/main.go @@ -31,6 +31,7 @@ import ( "flag" "fmt" "go/ast" + "go/build" "http" _ "http/pprof" // to serve /debug/pprof/* "io" @@ -332,7 +333,10 @@ func main() { } relpath := path abspath := path - if !filepath.IsAbs(path) { + if t, pkg, err := build.FindTree(path); err == nil { + relpath = pkg + abspath = filepath.Join(t.SrcDir(), pkg) + } else if !filepath.IsAbs(path) { abspath = absolutePath(path, pkgHandler.fsRoot) } else { relpath = relativeURL(path) diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go index 73f1881a2..92614e83e 100644 --- a/src/cmd/godoc/mapping.go +++ b/src/cmd/godoc/mapping.go @@ -59,10 +59,10 @@ type mapping struct { } -// Init initializes the Mapping from a list of paths separated by -// filepath.ListSeparator. Empty paths are ignored; relative paths -// are assumed to be relative to the current working directory and -// converted to absolute paths. For each path of the form: +// Init initializes the Mapping from a list of paths. +// Empty paths are ignored; relative paths are assumed to be relative to +// the current working directory and converted to absolute paths. +// For each path of the form: // // dirname/localname // @@ -80,8 +80,8 @@ type mapping struct { // user -> /home/user // public -> /home/build/public // -func (m *Mapping) Init(paths string) { - pathlist := canonicalizePaths(filepath.SplitList(paths), nil) +func (m *Mapping) Init(paths []string) { + pathlist := canonicalizePaths(paths, nil) list := make([]mapping, len(pathlist)) // create mapping list @@ -120,7 +120,7 @@ func (m *Mapping) PrefixList() []string { } // sort the list and remove duplicate entries - sort.SortStrings(list) + sort.Strings(list) i := 0 prev := "" for _, path := range list { diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go index 660bf6d04..e2637ab3d 100644 --- a/src/cmd/godoc/utils.go +++ b/src/cmd/godoc/utils.go @@ -80,7 +80,7 @@ func canonicalizePaths(list []string, filter func(path string) bool) []string { list = list[0:i] // sort the list and remove duplicate entries - sort.SortStrings(list) + sort.Strings(list) i = 0 prev := "" for _, path := range list { diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile index b157649e8..7ce21e8aa 100644 --- a/src/cmd/gofix/Makefile +++ b/src/cmd/gofix/Makefile @@ -6,16 +6,22 @@ include ../../Make.inc TARG=gofix GOFILES=\ + filepath.go\ fix.go\ - netdial.go\ - main.go\ - oserrorstring.go\ - osopen.go\ httpfinalurl.go\ + httpfs.go\ httpheaders.go\ httpserver.go\ + main.go\ + netdial.go\ + oserrorstring.go\ + osopen.go\ procattr.go\ reflect.go\ + signal.go\ + sorthelpers.go\ + sortslice.go\ + stringssplit.go\ typecheck.go\ include ../../Make.cmd diff --git a/src/cmd/gofix/filepath.go b/src/cmd/gofix/filepath.go new file mode 100644 index 000000000..1d0ad6879 --- /dev/null +++ b/src/cmd/gofix/filepath.go @@ -0,0 +1,53 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/ast" +) + +func init() { + register(fix{ + "filepath", + filepathFunc, + `Adapt code from filepath.[List]SeparatorString to string(filepath.[List]Separator). + +http://codereview.appspot.com/4527090 +`, + }) +} + +func filepathFunc(f *ast.File) (fixed bool) { + if !imports(f, "path/filepath") { + return + } + + walk(f, func(n interface{}) { + e, ok := n.(*ast.Expr) + if !ok { + return + } + + var ident string + switch { + case isPkgDot(*e, "filepath", "SeparatorString"): + ident = "filepath.Separator" + case isPkgDot(*e, "filepath", "ListSeparatorString"): + ident = "filepath.ListSeparator" + default: + return + } + + // string(filepath.[List]Separator) + *e = &ast.CallExpr{ + Fun: ast.NewIdent("string"), + Args: []ast.Expr{ast.NewIdent(ident)}, + } + + fixed = true + }) + + return +} diff --git a/src/cmd/gofix/filepath_test.go b/src/cmd/gofix/filepath_test.go new file mode 100644 index 000000000..d170c3ae3 --- /dev/null +++ b/src/cmd/gofix/filepath_test.go @@ -0,0 +1,33 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func init() { + addTestCases(filepathTests) +} + +var filepathTests = []testCase{ + { + Name: "filepath.0", + In: `package main + +import ( + "path/filepath" +) + +var _ = filepath.SeparatorString +var _ = filepath.ListSeparatorString +`, + Out: `package main + +import ( + "path/filepath" +) + +var _ = string(filepath.Separator) +var _ = string(filepath.ListSeparator) +`, + }, +} diff --git a/src/cmd/gofix/fix.go b/src/cmd/gofix/fix.go index 0852ce21e..c1c5a746c 100644 --- a/src/cmd/gofix/fix.go +++ b/src/cmd/gofix/fix.go @@ -10,6 +10,7 @@ import ( "go/token" "os" "strconv" + "strings" ) type fix struct { @@ -258,13 +259,28 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) { // imports returns true if f imports path. func imports(f *ast.File, path string) bool { + return importSpec(f, path) != nil +} + +// importSpec returns the import spec if f imports path, +// or nil otherwise. +func importSpec(f *ast.File, path string) *ast.ImportSpec { for _, s := range f.Imports { - t, err := strconv.Unquote(s.Path.Value) - if err == nil && t == path { - return true + if importPath(s) == path { + return s } } - return false + return nil +} + +// importPath returns the unquoted import path of s, +// or "" if the path is not properly quoted. +func importPath(s *ast.ImportSpec) string { + t, err := strconv.Unquote(s.Path.Value) + if err == nil { + return t + } + return "" } // isPkgDot returns true if t is the expression "pkg.name" @@ -420,3 +436,138 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr { }, } } + +// addImport adds the import path to the file f, if absent. +func addImport(f *ast.File, path string) { + if imports(f, path) { + return + } + + newImport := &ast.ImportSpec{ + Path: &ast.BasicLit{ + Kind: token.STRING, + Value: strconv.Quote(path), + }, + } + + var impdecl *ast.GenDecl + + // Find an import decl to add to. + for _, decl := range f.Decls { + gen, ok := decl.(*ast.GenDecl) + + if ok && gen.Tok == token.IMPORT { + impdecl = gen + break + } + } + + // No import decl found. Add one. + if impdecl == nil { + impdecl = &ast.GenDecl{ + Tok: token.IMPORT, + } + f.Decls = append(f.Decls, nil) + copy(f.Decls[1:], f.Decls) + f.Decls[0] = impdecl + } + + // Ensure the import decl has parentheses, if needed. + if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() { + impdecl.Lparen = impdecl.Pos() + } + + // Assume the import paths are alphabetically ordered. + // If they are not, the result is ugly, but legal. + insertAt := len(impdecl.Specs) // default to end of specs + for i, spec := range impdecl.Specs { + impspec := spec.(*ast.ImportSpec) + if importPath(impspec) > path { + insertAt = i + break + } + } + + impdecl.Specs = append(impdecl.Specs, nil) + copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:]) + impdecl.Specs[insertAt] = newImport + + f.Imports = append(f.Imports, newImport) +} + +// deleteImport deletes the import path from the file f, if present. +func deleteImport(f *ast.File, path string) { + oldImport := importSpec(f, path) + + // Find the import node that imports path, if any. + for i, decl := range f.Decls { + gen, ok := decl.(*ast.GenDecl) + if !ok || gen.Tok != token.IMPORT { + continue + } + for j, spec := range gen.Specs { + impspec := spec.(*ast.ImportSpec) + + if oldImport != impspec { + continue + } + + // We found an import spec that imports path. + // Delete it. + copy(gen.Specs[j:], gen.Specs[j+1:]) + gen.Specs = gen.Specs[:len(gen.Specs)-1] + + // If this was the last import spec in this decl, + // delete the decl, too. + if len(gen.Specs) == 0 { + copy(f.Decls[i:], f.Decls[i+1:]) + f.Decls = f.Decls[:len(f.Decls)-1] + } else if len(gen.Specs) == 1 { + gen.Lparen = token.NoPos // drop parens + } + + break + } + } + + // Delete it from f.Imports. + for i, imp := range f.Imports { + if imp == oldImport { + copy(f.Imports[i:], f.Imports[i+1:]) + f.Imports = f.Imports[:len(f.Imports)-1] + break + } + } +} + +func usesImport(f *ast.File, path string) (used bool) { + spec := importSpec(f, path) + if spec == nil { + return + } + + name := spec.Name.String() + switch name { + case "<nil>": + // If the package name is not explicitly specified, + // make an educated guess. This is not guaranteed to be correct. + lastSlash := strings.LastIndex(path, "/") + if lastSlash == -1 { + name = path + } else { + name = path[lastSlash+1:] + } + case "_", ".": + // Not sure if this import is used - err on the side of caution. + return true + } + + walk(f, func(n interface{}) { + sel, ok := n.(*ast.SelectorExpr) + if ok && isTopName(sel.X, name) { + used = true + } + }) + + return +} diff --git a/src/cmd/gofix/httpfs.go b/src/cmd/gofix/httpfs.go new file mode 100644 index 000000000..7f2765680 --- /dev/null +++ b/src/cmd/gofix/httpfs.go @@ -0,0 +1,63 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/ast" + "go/token" +) + +var httpFileSystemFix = fix{ + "httpfs", + httpfs, + `Adapt http FileServer to take a FileSystem. + +http://codereview.appspot.com/4629047 http FileSystem interface +`, +} + +func init() { + register(httpFileSystemFix) +} + +func httpfs(f *ast.File) bool { + if !imports(f, "http") { + return false + } + + fixed := false + walk(f, func(n interface{}) { + call, ok := n.(*ast.CallExpr) + if !ok || !isPkgDot(call.Fun, "http", "FileServer") { + return + } + if len(call.Args) != 2 { + return + } + dir, prefix := call.Args[0], call.Args[1] + call.Args = []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("Dir")}, + Args: []ast.Expr{dir}, + }} + wrapInStripHandler := true + if prefixLit, ok := prefix.(*ast.BasicLit); ok { + if prefixLit.Kind == token.STRING && (prefixLit.Value == `"/"` || prefixLit.Value == `""`) { + wrapInStripHandler = false + } + } + if wrapInStripHandler { + call.Fun.(*ast.SelectorExpr).Sel = ast.NewIdent("StripPrefix") + call.Args = []ast.Expr{ + prefix, + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("FileServer")}, + Args: call.Args, + }, + } + } + fixed = true + }) + return fixed +} diff --git a/src/cmd/gofix/httpfs_test.go b/src/cmd/gofix/httpfs_test.go new file mode 100644 index 000000000..d1804e93b --- /dev/null +++ b/src/cmd/gofix/httpfs_test.go @@ -0,0 +1,47 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func init() { + addTestCases(httpFileSystemTests) +} + +var httpFileSystemTests = []testCase{ + { + Name: "httpfs.0", + In: `package httpfs + +import ( + "http" +) + +func f() { + _ = http.FileServer("/var/www/foo", "/") + _ = http.FileServer("/var/www/foo", "") + _ = http.FileServer("/var/www/foo/bar", "/bar") + s := "/foo" + _ = http.FileServer(s, "/") + prefix := "/p" + _ = http.FileServer(s, prefix) +} +`, + Out: `package httpfs + +import ( + "http" +) + +func f() { + _ = http.FileServer(http.Dir("/var/www/foo")) + _ = http.FileServer(http.Dir("/var/www/foo")) + _ = http.StripPrefix("/bar", http.FileServer(http.Dir("/var/www/foo/bar"))) + s := "/foo" + _ = http.FileServer(http.Dir(s)) + prefix := "/p" + _ = http.StripPrefix(prefix, http.FileServer(http.Dir(s))) +} +`, + }, +} diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go index 05495bc0d..e7e7013c5 100644 --- a/src/cmd/gofix/main.go +++ b/src/cmd/gofix/main.go @@ -53,7 +53,7 @@ func main() { if *allowedRewrites != "" { allowed = make(map[string]bool) - for _, f := range strings.Split(*allowedRewrites, ",", -1) { + for _, f := range strings.Split(*allowedRewrites, ",") { allowed[f] = true } } diff --git a/src/cmd/gofix/signal.go b/src/cmd/gofix/signal.go new file mode 100644 index 000000000..53c338851 --- /dev/null +++ b/src/cmd/gofix/signal.go @@ -0,0 +1,49 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/ast" + "strings" +) + +func init() { + register(fix{ + "signal", + signal, + `Adapt code to types moved from os/signal to signal. + +http://codereview.appspot.com/4437091 +`, + }) +} + +func signal(f *ast.File) (fixed bool) { + if !imports(f, "os/signal") { + return + } + + walk(f, func(n interface{}) { + s, ok := n.(*ast.SelectorExpr) + + if !ok || !isTopName(s.X, "signal") { + return + } + + sel := s.Sel.String() + if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") { + s.X = &ast.Ident{Name: "os"} + fixed = true + } + }) + + if fixed { + addImport(f, "os") + if !usesImport(f, "os/signal") { + deleteImport(f, "os/signal") + } + } + return +} diff --git a/src/cmd/gofix/signal_test.go b/src/cmd/gofix/signal_test.go new file mode 100644 index 000000000..2500e9cee --- /dev/null +++ b/src/cmd/gofix/signal_test.go @@ -0,0 +1,96 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func init() { + addTestCases(signalTests) +} + +var signalTests = []testCase{ + { + Name: "signal.0", + In: `package main + +import ( + _ "a" + "os/signal" + _ "z" +) + +type T1 signal.UnixSignal +type T2 signal.Signal + +func f() { + _ = signal.SIGHUP + _ = signal.Incoming +} +`, + Out: `package main + +import ( + _ "a" + "os" + "os/signal" + _ "z" +) + +type T1 os.UnixSignal +type T2 os.Signal + +func f() { + _ = os.SIGHUP + _ = signal.Incoming +} +`, + }, + { + Name: "signal.1", + In: `package main + +import ( + "os" + "os/signal" +) + +func f() { + var _ os.Error + _ = signal.SIGHUP +} +`, + Out: `package main + +import "os" + + +func f() { + var _ os.Error + _ = os.SIGHUP +} +`, + }, + { + Name: "signal.2", + In: `package main + +import "os" +import "os/signal" + +func f() { + var _ os.Error + _ = signal.SIGHUP +} +`, + Out: `package main + +import "os" + + +func f() { + var _ os.Error + _ = os.SIGHUP +} +`, + }, +} diff --git a/src/cmd/gofix/sorthelpers.go b/src/cmd/gofix/sorthelpers.go new file mode 100644 index 000000000..4d0bee6e7 --- /dev/null +++ b/src/cmd/gofix/sorthelpers.go @@ -0,0 +1,47 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/ast" +) + +func init() { + register(fix{ + "sorthelpers", + sorthelpers, + `Adapt code from sort.Sort[Ints|Float64s|Strings] to sort.[Ints|Float64s|Strings]. +`, + }) +} + + +func sorthelpers(f *ast.File) (fixed bool) { + if !imports(f, "sort") { + return + } + + walk(f, func(n interface{}) { + s, ok := n.(*ast.SelectorExpr) + if !ok || !isTopName(s.X, "sort") { + return + } + + switch s.Sel.String() { + case "SortFloat64s": + s.Sel.Name = "Float64s" + case "SortInts": + s.Sel.Name = "Ints" + case "SortStrings": + s.Sel.Name = "Strings" + default: + return + } + + fixed = true + }) + + return +} diff --git a/src/cmd/gofix/sorthelpers_test.go b/src/cmd/gofix/sorthelpers_test.go new file mode 100644 index 000000000..6c37858fd --- /dev/null +++ b/src/cmd/gofix/sorthelpers_test.go @@ -0,0 +1,45 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func init() { + addTestCases(sorthelpersTests) +} + +var sorthelpersTests = []testCase{ + { + Name: "sortslice.0", + In: `package main + +import ( + "sort" +) + +func main() { + var s []string + sort.SortStrings(s) + var i []ints + sort.SortInts(i) + var f []float64 + sort.SortFloat64s(f) +} +`, + Out: `package main + +import ( + "sort" +) + +func main() { + var s []string + sort.Strings(s) + var i []ints + sort.Ints(i) + var f []float64 + sort.Float64s(f) +} +`, + }, +} diff --git a/src/cmd/gofix/sortslice.go b/src/cmd/gofix/sortslice.go new file mode 100644 index 000000000..b9c108b5a --- /dev/null +++ b/src/cmd/gofix/sortslice.go @@ -0,0 +1,50 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/ast" +) + +func init() { + register(fix{ + "sortslice", + sortslice, + `Adapt code from sort.[Float64|Int|String]Array to sort.[Float64|Int|String]Slice. + +http://codereview.appspot.com/4602054 +http://codereview.appspot.com/4639041 +`, + }) +} + + +func sortslice(f *ast.File) (fixed bool) { + if !imports(f, "sort") { + return + } + + walk(f, func(n interface{}) { + s, ok := n.(*ast.SelectorExpr) + if !ok || !isTopName(s.X, "sort") { + return + } + + switch s.Sel.String() { + case "Float64Array": + s.Sel.Name = "Float64Slice" + case "IntArray": + s.Sel.Name = "IntSlice" + case "StringArray": + s.Sel.Name = "StringSlice" + default: + return + } + + fixed = true + }) + + return +} diff --git a/src/cmd/gofix/sortslice_test.go b/src/cmd/gofix/sortslice_test.go new file mode 100644 index 000000000..404feb26f --- /dev/null +++ b/src/cmd/gofix/sortslice_test.go @@ -0,0 +1,35 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func init() { + addTestCases(sortsliceTests) +} + +var sortsliceTests = []testCase{ + { + Name: "sortslice.0", + In: `package main + +import ( + "sort" +) + +var _ = sort.Float64Array +var _ = sort.IntArray +var _ = sort.StringArray +`, + Out: `package main + +import ( + "sort" +) + +var _ = sort.Float64Slice +var _ = sort.IntSlice +var _ = sort.StringSlice +`, + }, +} diff --git a/src/cmd/gofix/stringssplit.go b/src/cmd/gofix/stringssplit.go new file mode 100644 index 000000000..4a1fe93d3 --- /dev/null +++ b/src/cmd/gofix/stringssplit.go @@ -0,0 +1,71 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/ast" + "go/token" +) + +var stringssplitFix = fix{ + "stringssplit", + stringssplit, + `Restore strings.Split to its original meaning and add strings.SplitN. Bytes too. + +http://codereview.appspot.com/4661051 +`, +} + +func init() { + register(stringssplitFix) +} + +func stringssplit(f *ast.File) bool { + if !imports(f, "bytes") && !imports(f, "strings") { + return false + } + + fixed := false + walk(f, func(n interface{}) { + call, ok := n.(*ast.CallExpr) + // func Split(s, sep string, n int) []string + // func SplitAfter(s, sep string, n int) []string + if !ok || len(call.Args) != 3 { + return + } + // Is this our function? + switch { + case isPkgDot(call.Fun, "bytes", "Split"): + case isPkgDot(call.Fun, "bytes", "SplitAfter"): + case isPkgDot(call.Fun, "strings", "Split"): + case isPkgDot(call.Fun, "strings", "SplitAfter"): + default: + return + } + + sel := call.Fun.(*ast.SelectorExpr) + args := call.Args + fixed = true // We're committed. + + // Is the last argument -1? If so, drop the arg. + // (Actually we just look for a negative integer literal.) + // Otherwise, Split->SplitN and keep the arg. + final := args[2] + if unary, ok := final.(*ast.UnaryExpr); ok && unary.Op == token.SUB { + if lit, ok := unary.X.(*ast.BasicLit); ok { + // Is it an integer? If so, it's a negative integer and that's what we're after. + if lit.Kind == token.INT { + // drop the last arg. + call.Args = args[0:2] + return + } + } + } + + // If not, rename and keep the argument list. + sel.Sel.Name += "N" + }) + return fixed +} diff --git a/src/cmd/gofix/stringssplit_test.go b/src/cmd/gofix/stringssplit_test.go new file mode 100644 index 000000000..b925722af --- /dev/null +++ b/src/cmd/gofix/stringssplit_test.go @@ -0,0 +1,51 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func init() { + addTestCases(stringssplitTests) +} + +var stringssplitTests = []testCase{ + { + Name: "stringssplit.0", + In: `package main + +import ( + "bytes" + "strings" +) + +func f() { + bytes.Split(a, b, c) + bytes.Split(a, b, -1) + bytes.SplitAfter(a, b, c) + bytes.SplitAfter(a, b, -1) + strings.Split(a, b, c) + strings.Split(a, b, -1) + strings.SplitAfter(a, b, c) + strings.SplitAfter(a, b, -1) +} +`, + Out: `package main + +import ( + "bytes" + "strings" +) + +func f() { + bytes.SplitN(a, b, c) + bytes.Split(a, b) + bytes.SplitAfterN(a, b, c) + bytes.SplitAfter(a, b) + strings.SplitN(a, b, c) + strings.Split(a, b) + strings.SplitAfterN(a, b, c) + strings.SplitAfter(a, b) +} +`, + }, +} diff --git a/src/cmd/gofix/testdata/reflect.template.go.in b/src/cmd/gofix/testdata/reflect.template.go.in index ba06de4e3..1f5a8128f 100644 --- a/src/cmd/gofix/testdata/reflect.template.go.in +++ b/src/cmd/gofix/testdata/reflect.template.go.in @@ -444,7 +444,7 @@ func (t *Template) newVariable(words []string) *variableElement { bar := strings.IndexRune(lastWord, '|') if bar >= 0 { words[len(words)-1] = lastWord[0:bar] - formatters = strings.Split(lastWord[bar+1:], "|", -1) + formatters = strings.Split(lastWord[bar+1:], "|") } // We could remember the function address here and avoid the lookup later, @@ -705,7 +705,7 @@ func (t *Template) findVar(st *state, s string) reflect.Value { if s == "@" { return indirectPtr(data, numStars) } - for _, elem := range strings.Split(s, ".", -1) { + for _, elem := range strings.Split(s, ".") { // Look up field; data must be a struct or map. data = t.lookup(st, data, elem) if data == nil { diff --git a/src/cmd/gofix/testdata/reflect.template.go.out b/src/cmd/gofix/testdata/reflect.template.go.out index c36288455..f2f56ef3c 100644 --- a/src/cmd/gofix/testdata/reflect.template.go.out +++ b/src/cmd/gofix/testdata/reflect.template.go.out @@ -444,7 +444,7 @@ func (t *Template) newVariable(words []string) *variableElement { bar := strings.IndexRune(lastWord, '|') if bar >= 0 { words[len(words)-1] = lastWord[0:bar] - formatters = strings.Split(lastWord[bar+1:], "|", -1) + formatters = strings.Split(lastWord[bar+1:], "|") } // We could remember the function address here and avoid the lookup later, @@ -705,7 +705,7 @@ func (t *Template) findVar(st *state, s string) reflect.Value { if s == "@" { return indirectPtr(data, numStars) } - for _, elem := range strings.Split(s, ".", -1) { + for _, elem := range strings.Split(s, ".") { // Look up field; data must be a struct or map. data = t.lookup(st, data, elem) if !data.IsValid() { diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go index a72530307..70700554b 100644 --- a/src/cmd/gofmt/gofmt_test.go +++ b/src/cmd/gofmt/gofmt_test.go @@ -20,8 +20,8 @@ func runTest(t *testing.T, dirname, in, out, flags string) { // process flags *simplifyAST = false *rewriteRule = "" - for _, flag := range strings.Split(flags, " ", -1) { - elts := strings.Split(flag, "=", 2) + for _, flag := range strings.Split(flags, " ") { + elts := strings.SplitN(flag, "=", 2) name := elts[0] value := "" if len(elts) == 2 { diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go index 4c24282f3..f7f1fe824 100644 --- a/src/cmd/gofmt/rewrite.go +++ b/src/cmd/gofmt/rewrite.go @@ -22,7 +22,7 @@ func initRewrite() { rewrite = nil // disable any previous rewrite return } - f := strings.Split(*rewriteRule, "->", -1) + f := strings.Split(*rewriteRule, "->") if len(f) != 2 { fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n") os.Exit(2) diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go index 52b09d37e..a5df7b3bd 100644 --- a/src/cmd/goinstall/doc.go +++ b/src/cmd/goinstall/doc.go @@ -5,7 +5,8 @@ /* Goinstall is an experiment in automatic package installation. It installs packages, possibly downloading them from the internet. -It maintains a list of public Go packages at http://godashboard.appspot.com/package. +It maintains a list of public Go packages at +http://godashboard.appspot.com/package. Usage: goinstall [flags] importpath... @@ -41,9 +42,22 @@ Another common idiom is to use to update, recompile, and reinstall all goinstalled packages. The source code for a package with import path foo/bar is expected -to be in the directory $GOROOT/src/pkg/foo/bar/. If the import -path refers to a code hosting site, goinstall will download the code -if necessary. The recognized code hosting sites are: +to be in the directory $GOROOT/src/pkg/foo/bar/ or $GOPATH/src/foo/bar/. +See "The GOPATH Environment Variable" for more about GOPATH. + +By default, goinstall prints output only when it encounters an error. +The -v flag causes goinstall to print information about packages +being considered and installed. + +Goinstall ignores Makefiles. + + +Remote Repositories + +If a package import path refers to a remote repository, goinstall will +download the code if necessary. + +Goinstall recognizes packages from a few common code hosting sites: BitBucket (Mercurial) @@ -72,7 +86,6 @@ if necessary. The recognized code hosting sites are: import "launchpad.net/~user/project/branch" import "launchpad.net/~user/project/branch/sub/directory" - If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project) already exists and contains an appropriate checkout, goinstall will not attempt to fetch updates. The -u flag changes this behavior, @@ -84,19 +97,42 @@ named "release". If there is one, it uses that version of the code. Otherwise it uses the default version selected by the version control system, typically HEAD for git, tip for Mercurial. -After a successful download and installation of a publicly accessible -remote package, goinstall reports the installation to godashboard.appspot.com, -which increments a count associated with the package and the time -of its most recent installation. This mechanism powers the package list -at http://godashboard.appspot.com/package, allowing Go programmers -to learn about popular packages that might be worth looking at. +After a successful download and installation of one of these import paths, +goinstall reports the installation to godashboard.appspot.com, which +increments a count associated with the package and the time of its most +recent installation. This mechanism powers the package list at +http://godashboard.appspot.com/package, allowing Go programmers to learn about +popular packages that might be worth looking at. The -dashboard=false flag disables this reporting. -By default, goinstall prints output only when it encounters an error. -The -v flag causes goinstall to print information about packages -being considered and installed. +For code hosted on other servers, goinstall recognizes the general form + + repository.vcs/path + +as denoting the given repository, with or without the .vcs suffix, using +the named version control system, and then the path inside that repository. +The supported version control systems are: + + Bazaar .bzr + Git .git + Mercurial .hg + Subversion .svn + +For example, + + import "example.org/user/foo.hg" + +denotes the root directory of the Mercurial repository at example.org/user/foo +or foo.hg, and + + import "example.org/repo.git/foo/bar" + +denotes the foo/bar directory of the Git repository at example.com/repo or +repo.git. -Goinstall does not use make. Makefiles are ignored by goinstall. +When a version control system supports multiple protocols, goinstall tries each +in turn. +For example, for Git it tries git://, then https://, then http://. The GOPATH Environment Variable diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go index d209fa82b..da892a69d 100644 --- a/src/cmd/goinstall/download.go +++ b/src/cmd/goinstall/download.go @@ -7,6 +7,8 @@ package main import ( + "exec" + "fmt" "http" "os" "path/filepath" @@ -31,11 +33,6 @@ func maybeReportToDashboard(path string) { } } -type host struct { - pattern *regexp.Regexp - protocol string -} - // a vcs represents a version control system // like Mercurial, Git, or Subversion. type vcs struct { @@ -57,9 +54,10 @@ type vcs struct { defaultHosts []host } -type vcsMatch struct { - *vcs - prefix, repo string +type host struct { + pattern *regexp.Regexp + protocol string + suffix string } var hg = vcs{ @@ -75,10 +73,11 @@ var hg = vcs{ logLimitFlag: "-l1", logReleaseFlag: "-rrelease", check: "identify", - protocols: []string{"http"}, + protocols: []string{"https", "http"}, + suffix: ".hg", defaultHosts: []host{ - {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https"}, - {regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http"}, + {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""}, + {regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ""}, }, } @@ -94,11 +93,11 @@ var git = vcs{ log: "show-ref", logLimitFlag: "", logReleaseFlag: "release", - check: "peek-remote", - protocols: []string{"git", "http"}, + check: "ls-remote", + protocols: []string{"git", "https", "http"}, suffix: ".git", defaultHosts: []host{ - {regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http"}, + {regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ".git"}, }, } @@ -114,9 +113,10 @@ var svn = vcs{ logLimitFlag: "-l1", logReleaseFlag: "release", check: "info", - protocols: []string{"http", "svn"}, + protocols: []string{"https", "http", "svn"}, + suffix: ".svn", defaultHosts: []host{ - {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https"}, + {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""}, }, } @@ -134,23 +134,79 @@ var bzr = vcs{ logLimitFlag: "-l1", logReleaseFlag: "-rrelease", check: "info", - protocols: []string{"http", "bzr"}, + protocols: []string{"https", "http", "bzr"}, + suffix: ".bzr", defaultHosts: []host{ - {regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https"}, + {regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https", ""}, }, } var vcsList = []*vcs{&git, &hg, &bzr, &svn} +type vcsMatch struct { + *vcs + prefix, repo string +} + +// findHostedRepo checks whether pkg is located at one of +// the supported code hosting sites and, if so, returns a match. +func findHostedRepo(pkg string) (*vcsMatch, os.Error) { + for _, v := range vcsList { + for _, host := range v.defaultHosts { + if hm := host.pattern.FindStringSubmatch(pkg); hm != nil { + if host.suffix != "" && strings.HasSuffix(hm[1], host.suffix) { + return nil, os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix") + } + repo := host.protocol + "://" + hm[1] + host.suffix + return &vcsMatch{v, hm[1], repo}, nil + } + } + } + return nil, nil +} + +// findAnyRepo looks for a vcs suffix in pkg (.git, etc) and returns a match. +func findAnyRepo(pkg string) (*vcsMatch, os.Error) { + for _, v := range vcsList { + i := strings.Index(pkg+"/", v.suffix+"/") + if i < 0 { + continue + } + if !strings.Contains(pkg[:i], "/") { + continue // don't match vcs suffix in the host name + } + if m := v.find(pkg[:i]); m != nil { + return m, nil + } + return nil, fmt.Errorf("couldn't find %s repository", v.name) + } + return nil, nil +} + +func (v *vcs) find(pkg string) *vcsMatch { + for _, proto := range v.protocols { + for _, suffix := range []string{"", v.suffix} { + repo := proto + "://" + pkg + suffix + out, err := exec.Command(v.cmd, v.check, repo).CombinedOutput() + if err == nil { + printf("find %s: found %s\n", pkg, repo) + return &vcsMatch{v, pkg + v.suffix, repo} + } + printf("find %s: %s %s %s: %v\n%s\n", pkg, v.cmd, v.check, repo, err, out) + } + } + return nil +} + // isRemote returns true if the first part of the package name looks like a // hostname - i.e. contains at least one '.' and the last part is at least 2 // characters. func isRemote(pkg string) bool { - parts := strings.Split(pkg, "/", 2) + parts := strings.SplitN(pkg, "/", 2) if len(parts) != 2 { return false } - parts = strings.Split(parts[0], ".", -1) + parts = strings.Split(parts[0], ".") if len(parts) < 2 || len(parts[len(parts)-1]) < 2 { return false } @@ -158,26 +214,35 @@ func isRemote(pkg string) bool { } // download checks out or updates pkg from the remote server. -func download(pkg, srcDir string) os.Error { +func download(pkg, srcDir string) (dashReport bool, err os.Error) { if strings.Contains(pkg, "..") { - return os.NewError("invalid path (contains ..)") + err = os.NewError("invalid path (contains ..)") + return } - var m *vcsMatch - for _, v := range vcsList { - for _, host := range v.defaultHosts { - if hm := host.pattern.FindStringSubmatch(pkg); hm != nil { - if v.suffix != "" && strings.HasSuffix(hm[1], v.suffix) { - return os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix") - } - repo := host.protocol + "://" + hm[1] + v.suffix - m = &vcsMatch{v, hm[1], repo} - } + m, err := findHostedRepo(pkg) + if err != nil { + return + } + if m != nil { + dashReport = true // only report public code hosting sites + } else { + m, err = findAnyRepo(pkg) + if err != nil { + return } } if m == nil { - return os.NewError("cannot download: " + pkg) + err = os.NewError("cannot download: " + pkg) + return + } + installed, err := m.checkoutRepo(srcDir, m.prefix, m.repo) + if err != nil { + return + } + if !installed { + dashReport = false } - return vcsCheckout(m.vcs, srcDir, m.prefix, m.repo, pkg) + return } // Try to detect if a "release" tag exists. If it does, update @@ -196,47 +261,46 @@ func (v *vcs) updateRepo(dst string) os.Error { return nil } -// vcsCheckout checks out repo into dst using vcs. +// checkoutRepo checks out repo into dst using vcs. // It tries to check out (or update, if the dst already // exists and -u was specified on the command line) // the repository at tag/branch "release". If there is no // such tag or branch, it falls back to the repository tip. -func vcsCheckout(vcs *vcs, srcDir, pkgprefix, repo, dashpath string) os.Error { +func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) (installed bool, err os.Error) { dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix)) dir, err := os.Stat(filepath.Join(dst, vcs.metadir)) if err == nil && !dir.IsDirectory() { - return os.NewError("not a directory: " + dst) + err = os.NewError("not a directory: " + dst) + return } if err != nil { parent, _ := filepath.Split(dst) - if err := os.MkdirAll(parent, 0777); err != nil { - return err + if err = os.MkdirAll(parent, 0777); err != nil { + return } - if err := run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil { - return err + if err = run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil { + return } - if err := vcs.updateRepo(dst); err != nil { - return err + if err = vcs.updateRepo(dst); err != nil { + return } - // success on first installation - report - maybeReportToDashboard(dashpath) + installed = true } else if *update { // Retrieve new revisions from the remote branch, if the VCS // supports this operation independently (e.g. svn doesn't) if vcs.pull != "" { if vcs.pullForceFlag != "" { - if err := run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil { - return err + if err = run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil { + return } - } else if err := run(dst, nil, vcs.cmd, vcs.pull); err != nil { - return err + } else if err = run(dst, nil, vcs.cmd, vcs.pull); err != nil { + return } } - // Update to release or latest revision - if err := vcs.updateRepo(dst); err != nil { - return err + if err = vcs.updateRepo(dst); err != nil { + return } } - return nil + return } diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go index bdf8469a0..5cdf0f18e 100644 --- a/src/cmd/goinstall/main.go +++ b/src/cmd/goinstall/main.go @@ -182,9 +182,10 @@ func install(pkg, parent string) { } // Download remote packages if not found or forced with -u flag. remote := isRemote(pkg) + dashReport := false if remote && (err == build.ErrNotFound || (err == nil && *update)) { printf("%s: download\n", pkg) - err = download(pkg, tree.SrcDir()) + dashReport, err = download(pkg, tree.SrcDir()) } if err != nil { errorf("%s: %v\n", pkg, err) @@ -243,6 +244,9 @@ func install(pkg, parent string) { } } } + if dashReport { + maybeReportToDashboard(pkg) + } if remote { // mark package as installed in $GOROOT/goinstall.log logPackage(pkg) diff --git a/src/cmd/gotest/doc.go b/src/cmd/gotest/doc.go index 9dba390c1..5be06f817 100644 --- a/src/cmd/gotest/doc.go +++ b/src/cmd/gotest/doc.go @@ -53,7 +53,9 @@ The resulting test binary, called (for amd64) 6.out, has several flags. Usage: 6.out [-test.v] [-test.run pattern] [-test.bench pattern] \ [-test.cpuprofile=cpu.out] \ - [-test.memprofile=mem.out] [-test.memprofilerate=1] + [-test.memprofile=mem.out] [-test.memprofilerate=1] \ + [-test.timeout=10] [-test.short] \ + [-test.benchtime=3] [-test.cpu=1,2,3,4] The -test.v flag causes the tests to be logged as they run. The -test.run flag causes only those tests whose names match the regular @@ -93,6 +95,13 @@ The -test.timeout flag sets a timeout for the test in seconds. If the test runs for longer than that, it will panic, dumping a stack trace of all existing goroutines. +The -test.benchtime flag specifies the number of seconds to run each benchmark. +The default is one second. + +The -test.cpu flag specifies a list of GOMAXPROCS values for which +the tests or benchmarks are executed. The default is the current +value of GOMAXPROCS. + For convenience, each of these -test.X flags of the test binary is also available as the flag -X in gotest itself. Flags not listed here are unaffected. For instance, the command diff --git a/src/cmd/gotest/flag.go b/src/cmd/gotest/flag.go index 780c78b9c..c3a28f9a3 100644 --- a/src/cmd/gotest/flag.go +++ b/src/cmd/gotest/flag.go @@ -23,6 +23,8 @@ var usageMessage = `Usage of %s: // These flags can be passed with or without a "test." prefix: -v or -test.v. -bench="": passes -test.bench to test + -benchtime=1: passes -test.benchtime to test + -cpu="": passes -test.cpu to test -cpuprofile="": passes -test.cpuprofile to test -memprofile="": passes -test.memprofile to test -memprofilerate=0: passes -test.memprofilerate to test @@ -56,6 +58,8 @@ var flagDefn = []*flagSpec{ // passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v. &flagSpec{name: "bench", passToTest: true}, + &flagSpec{name: "benchtime", passToTest: true}, + &flagSpec{name: "cpu", passToTest: true}, &flagSpec{name: "cpuprofile", passToTest: true}, &flagSpec{name: "memprofile", passToTest: true}, &flagSpec{name: "memprofilerate", passToTest: true}, diff --git a/src/cmd/govet/Makefile b/src/cmd/govet/Makefile index 291b27197..f565b78f5 100644 --- a/src/cmd/govet/Makefile +++ b/src/cmd/govet/Makefile @@ -9,3 +9,6 @@ GOFILES=\ govet.go\ include ../../Make.cmd + +test testshort: $(TARG) + ../../../test/errchk $(TARG) -printfuncs='Warn:1,Warnf:1' govet.go diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go index b811c61a2..5b24d2ff0 100644 --- a/src/cmd/govet/govet.go +++ b/src/cmd/govet/govet.go @@ -15,6 +15,7 @@ import ( "go/token" "os" "path/filepath" + "reflect" "strconv" "strings" "utf8" @@ -50,7 +51,7 @@ func main() { flag.Parse() if *printfuncs != "" { - for _, name := range strings.Split(*printfuncs, ",", -1) { + for _, name := range strings.Split(*printfuncs, ",") { if len(name) == 0 { flag.Usage() } @@ -59,7 +60,7 @@ func main() { var err os.Error skip, err = strconv.Atoi(name[colon+1:]) if err != nil { - error(`illegal format for "Func:N" argument %q; %s`, name, err) + errorf(`illegal format for "Func:N" argument %q; %s`, name, err) } name = name[:colon] } @@ -93,7 +94,7 @@ func doFile(name string, reader io.Reader) { fs := token.NewFileSet() parsedFile, err := parser.ParseFile(fs, name, reader, 0) if err != nil { - error("%s: %s", name, err) + errorf("%s: %s", name, err) return } file := &File{fs.File(parsedFile.Pos())} @@ -121,7 +122,7 @@ func walkDir(root string) { done := make(chan bool) go func() { for e := range errors { - error("walk error: %s", e) + errorf("walk error: %s", e) } done <- true }() @@ -132,7 +133,7 @@ func walkDir(root string) { // error formats the error to standard error, adding program // identification and a newline -func error(format string, args ...interface{}) { +func errorf(format string, args ...interface{}) { fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...) setExit(2) } @@ -185,15 +186,35 @@ func (f *File) checkFile(name string, file *ast.File) { // Visit implements the ast.Visitor interface. func (f *File) Visit(node ast.Node) ast.Visitor { - // TODO: could return nil for nodes that cannot contain a CallExpr - - // will shortcut traversal. Worthwhile? switch n := node.(type) { case *ast.CallExpr: f.checkCallExpr(n) + case *ast.Field: + f.checkFieldTag(n) } return f } +// checkField checks a struct field tag. +func (f *File) checkFieldTag(field *ast.Field) { + if field.Tag == nil { + return + } + + tag, err := strconv.Unquote(field.Tag.Value) + if err != nil { + f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value) + return + } + + // Check tag for validity by appending + // new key:value to end and checking that + // the tag parsing code can find it. + if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" { + f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value) + return + } +} // checkCallExpr checks a call expression. func (f *File) checkCallExpr(call *ast.CallExpr) { @@ -358,19 +379,24 @@ func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) { } // This function never executes, but it serves as a simple test for the program. -// Test with govet -printfuncs="Bad:1,Badf:1,Warn:1,Warnf:1" govet.go +// Test with make test. func BadFunctionUsedInTests() { - fmt.Println() // niladic call - fmt.Println("%s", "hi") // % in call to Println - fmt.Printf("%s", "hi", 3) // wrong # percents - fmt.Printf("%s%%%d", "hi", 3) // right # percents - fmt.Printf("%.*d", 3, 3) // right # percents, with a * - fmt.Printf("%.*d", 3, 3, 3) // wrong # percents, with a * - printf("now is the time", "buddy") // no %s - Printf("now is the time", "buddy") // no %s + fmt.Println() // not an error + fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call" + fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args in Printf call" + fmt.Printf("%s%%%d", "hi", 3) // correct + fmt.Printf("%.*d", 3, 3) // correct + fmt.Printf("%.*d", 3, 3, 3) // ERROR "wrong number of args in Printf call" + printf("now is the time", "buddy") // ERROR "no formatting directive" + Printf("now is the time", "buddy") // ERROR "no formatting directive" + Printf("hi") // ok f := new(File) - f.Warn(0, "%s", "hello", 3) // % in call to added function - f.Warnf(0, "%s", "hello", 3) // wrong # %s in call to added function + f.Warn(0, "%s", "hello", 3) // ERROR "possible formatting directive in Warn call" + f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call" +} + +type BadTypeUsedInTests struct { + X int "hello" // ERROR "struct field tag" } // printf is used by the test. diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go index 220c99492..543f8b1e8 100644 --- a/src/cmd/goyacc/goyacc.go +++ b/src/cmd/goyacc/goyacc.go @@ -2834,7 +2834,7 @@ func others() { // copy yaccpar fmt.Fprintf(ftable, "\n//line yaccpar:1\n") - parts := strings.Split(yaccpar, prefix+"run()", 2) + parts := strings.SplitN(yaccpar, prefix+"run()", 2) fmt.Fprintf(ftable, "%v", parts[0]) ftable.Write(fcode.Bytes()) fmt.Fprintf(ftable, "%v", parts[1]) diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go index 1f3e5e736..4f7aec22b 100644 --- a/src/cmd/hgpatch/main.go +++ b/src/cmd/hgpatch/main.go @@ -176,7 +176,7 @@ func main() { list[i] = f i++ } - sort.SortStrings(list) + sort.Strings(list) for _, f := range list { fmt.Printf("%s\n", f) } @@ -282,7 +282,7 @@ func hgModified() ([]string, os.Error) { if err != nil { return nil, err } - return strings.Split(strings.TrimSpace(out), "\n", -1), nil + return strings.Split(strings.TrimSpace(out), "\n"), nil } // hgAdd adds name to the repository. diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index bdad58ff9..f1132fc8b 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -789,14 +789,34 @@ dodata(void) sect->vaddr = 0; datsize = 0; s = datap; - for(; s != nil && s->type < SDATA; s = s->next) { + for(; s != nil && s->type < SSYMTAB; s = s->next) { s->type = SRODATA; t = rnd(s->size, PtrSize); s->value = datsize; datsize += t; } sect->len = datsize - sect->vaddr; - + + /* gosymtab */ + sect = addsection(&segtext, ".gosymtab", 04); + sect->vaddr = datsize; + for(; s != nil && s->type < SPCLNTAB; s = s->next) { + s->type = SRODATA; + s->value = datsize; + datsize += s->size; + } + sect->len = datsize - sect->vaddr; + + /* gopclntab */ + sect = addsection(&segtext, ".gopclntab", 04); + sect->vaddr = datsize; + for(; s != nil && s->type < SDATA; s = s->next) { + s->type = SRODATA; + s->value = datsize; + datsize += s->size; + } + sect->len = datsize - sect->vaddr; + /* data */ datsize = 0; sect = addsection(&segdata, ".data", 06); @@ -890,7 +910,7 @@ textaddress(void) void address(void) { - Section *s, *text, *data, *rodata; + Section *s, *text, *data, *rodata, *symtab, *pclntab; Sym *sym, *sub; uvlong va; @@ -921,7 +941,9 @@ address(void) segdata.filelen = segdata.sect->len; // assume .data is first text = segtext.sect; - rodata = segtext.sect->next; + rodata = text->next; + symtab = rodata->next; + pclntab = symtab->next; data = segdata.sect; for(sym = datap; sym != nil; sym = sym->next) { @@ -938,12 +960,11 @@ address(void) xdefine("etext", STEXT, text->vaddr + text->len); xdefine("rodata", SRODATA, rodata->vaddr); xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); + xdefine("symtab", SRODATA, symtab->vaddr); + xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); + xdefine("pclntab", SRODATA, pclntab->vaddr); + xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len); xdefine("data", SBSS, data->vaddr); xdefine("edata", SBSS, data->vaddr + data->len); xdefine("end", SBSS, segdata.vaddr + segdata.len); - - sym = lookup("pclntab", 0); - xdefine("epclntab", SRODATA, sym->value + sym->size); - sym = lookup("symtab", 0); - xdefine("esymtab", SRODATA, sym->value + sym->size); } diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 04ee790a4..77a62f5de 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -956,7 +956,7 @@ pclntab(void) uchar *bp; sym = lookup("pclntab", 0); - sym->type = SRODATA; + sym->type = SPCLNTAB; sym->reachable = 1; if(debug['s']) return; diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 463713143..347987195 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -40,6 +40,8 @@ enum SSTRING, SGOSTRING, SRODATA, + SSYMTAB, + SPCLNTAB, SDATA, SMACHO, /* Mach-O __nl_symbol_ptr */ SMACHOGOT, diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index c66eca148..60e146b35 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -351,7 +351,7 @@ symtab(void) s->reachable = 1; symt = lookup("symtab", 0); - symt->type = SRODATA; + symt->type = SSYMTAB; symt->size = 0; symt->reachable = 1; @@ -372,5 +372,7 @@ symtab(void) } } + if(debug['s']) + return; genasmsym(putsymb); } |
