Ejemplo n.º 1
0
func rstComment(cgrp *ast.CommentGroup) (string, bool) {
	s := cgrp.Text()
	parts := strings.SplitN(s, "\n", 2)
	if strings.TrimSpace(parts[0]) == "+rst" {
		return parts[1], true
	}
	return "", false
}
Ejemplo n.º 2
0
func (r *reader) readDoc(comment *ast.CommentGroup) {
	// By convention there should be only one package comment
	// but collect all of them if there are more then one.
	text := comment.Text()
	if r.doc == "" {
		r.doc = text
		return
	}
	r.doc += "\n" + text
}
Ejemplo n.º 3
0
// lintPackageComment checks package comments. It complains if
// there is no package comment, or if it is not of the right form.
// This has a notable false positive in that a package comment
// could rightfully appear in a different file of the same package,
// but that's not easy to fix since this linter is file-oriented.
func (f *file) lintPackageComment() {
	if f.isTest() {
		return
	}

	const ref = styleGuideBase + "#package-comments"
	prefix := "Package " + f.f.Name.Name + " "

	// Look for a detached package comment.
	// First, scan for the last comment that occurs before the "package" keyword.
	var lastCG *ast.CommentGroup
	for _, cg := range f.f.Comments {
		if cg.Pos() > f.f.Package {
			// Gone past "package" keyword.
			break
		}
		lastCG = cg
	}
	if lastCG != nil && strings.HasPrefix(lastCG.Text(), prefix) {
		endPos := f.fset.Position(lastCG.End())
		pkgPos := f.fset.Position(f.f.Package)
		if endPos.Line+1 < pkgPos.Line {
			// There isn't a great place to anchor this error;
			// the start of the blank lines between the doc and the package statement
			// is at least pointing at the location of the problem.
			pos := token.Position{
				Filename: endPos.Filename,
				// Offset not set; it is non-trivial, and doesn't appear to be needed.
				Line:   endPos.Line + 1,
				Column: 1,
			}
			f.pkg.errorfAt(pos, 0.9, link(ref), category("comments"), "package comment is detached; there should be no blank lines between it and the package statement")
			return
		}
	}

	if f.f.Doc == nil {
		f.errorf(f.f, 0.2, link(ref), category("comments"), "should have a package comment, unless it's in another file for this package")
		return
	}
	s := f.f.Doc.Text()
	if ts := strings.TrimLeft(s, " \t"); ts != s {
		f.errorf(f.f.Doc, 1, link(ref), category("comments"), "package comment should not have leading space")
		s = ts
	}
	// Only non-main packages need to keep to this form.
	if f.f.Name.Name != "main" && !strings.HasPrefix(s, prefix) {
		f.errorf(f.f.Doc, 1, link(ref), category("comments"), `package comment should be of the form "%s..."`, prefix)
	}
}
Ejemplo n.º 4
0
func getComment(c *ast.CommentGroup) string {

	if c == nil {
		return ""
	}

	fmt.Println(c.Text())
	for _, lc := range c.List {
		fmt.Println(lc.Text)
	}

	return c.Text()

}
Ejemplo n.º 5
0
// lintTypeDoc examines the doc comment on a type.
// It complains if they are missing from an exported type,
// or if they are not of the standard form.
func (f *file) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) {
	if !ast.IsExported(t.Name.Name) {
		return
	}
	if doc == nil {
		f.errorf(t, 1, link(docCommentsLink), category("comments"), "exported type %v should have comment or be unexported", t.Name)
		return
	}

	s := doc.Text()
	articles := [...]string{"A", "An", "The"}
	for _, a := range articles {
		if strings.HasPrefix(s, a+" ") {
			s = s[len(a)+1:]
			break
		}
	}
	if !strings.HasPrefix(s, t.Name.Name+" ") {
		f.errorf(doc, 1, link(docCommentsLink), category("comments"), `comment on exported type %v should be of the form "%v ..." (with optional leading article)`, t.Name, t.Name)
	}
}
Ejemplo n.º 6
0
func exampleOutput(fun *ast.FuncDecl, comments []*ast.CommentGroup) string {
	// find the last comment in the function
	var last *ast.CommentGroup
	for _, cg := range comments {
		if cg.Pos() < fun.Pos() {
			continue
		}
		if cg.End() > fun.End() {
			break
		}
		last = cg
	}
	if last != nil {
		// test that it begins with the correct prefix
		text := last.Text()
		if loc := outputPrefix.FindStringIndex(text); loc != nil {
			return strings.TrimSpace(text[loc[1]:])
		}
	}
	return "" // no suitable comment found
}
Ejemplo n.º 7
0
// saveCgo saves the information from the #cgo lines in the import "C" comment.
// These lines set CFLAGS and LDFLAGS and pkg-config directives that affect
// the way cgo's C code is built.
//
// TODO(rsc): This duplicates code in cgo.
// Once the dust settles, remove this code from cgo.
func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
	text := cg.Text()
	for _, line := range strings.Split(text, "\n") {
		orig := line

		// Line is
		//	#cgo [GOOS/GOARCH...] LDFLAGS: stuff
		//
		line = strings.TrimSpace(line)
		if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
			continue
		}

		// Split at colon.
		line = strings.TrimSpace(line[4:])
		i := strings.Index(line, ":")
		if i < 0 {
			return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
		}
		line, argstr := line[:i], line[i+1:]

		// Parse GOOS/GOARCH stuff.
		f := strings.Fields(line)
		if len(f) < 1 {
			return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
		}

		cond, verb := f[:len(f)-1], f[len(f)-1]
		if len(cond) > 0 {
			ok := false
			for _, c := range cond {
				if ctxt.match(c) {
					ok = true
					break
				}
			}
			if !ok {
				continue
			}
		}

		args, err := splitQuoted(argstr)
		if err != nil {
			return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
		}
		for _, arg := range args {
			if !safeName(arg) {
				return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
			}
		}

		switch verb {
		case "CFLAGS":
			di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
		case "LDFLAGS":
			di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
		case "pkg-config":
			di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
		default:
			return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
		}
	}
	return nil
}
Ejemplo n.º 8
0
Archivo: pkg.go Proyecto: tompao/gb
// saveCgo saves the information from the #cgo lines in the import "C" comment.
// These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
// that affect the way cgo's C code is built.
func saveCgo(di *Package, filename string, cg *ast.CommentGroup) error {
	r := strings.NewReader(cg.Text())
	sc := bufio.NewScanner(r)
	for sc.Scan() {
		line := sc.Text()

		// Line is
		//	#cgo [GOOS/GOARCH...] LDFLAGS: stuff
		//
		line = strings.TrimSpace(line)
		if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
			continue
		}

		// Split at colon.
		line = strings.TrimSpace(line[4:])
		i := strings.Index(line, ":")
		if i < 0 {
			return fmt.Errorf("%s: invalid #cgo line: %s", filename, sc.Text())
		}
		line, argstr := line[:i], line[i+1:]

		// Parse GOOS/GOARCH stuff.
		f := strings.Fields(line)
		if len(f) < 1 {
			return fmt.Errorf("%s: invalid #cgo line: %s", filename, sc.Text())
		}

		cond, verb := f[:len(f)-1], f[len(f)-1]
		if len(cond) > 0 {
			ok := false
			for _, c := range cond {
				if di.match(c, nil) {
					ok = true
					break
				}
			}
			if !ok {
				continue
			}
		}

		args, err := splitQuoted(argstr)
		if err != nil {
			return fmt.Errorf("%s: invalid #cgo line: %s", filename, sc.Text())
		}
		for i, arg := range args {
			arg, ok := expandSrcDir(arg, di.Dir)
			if !ok {
				return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
			}
			args[i] = arg
		}

		switch verb {
		case "CFLAGS":
			di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
		case "CPPFLAGS":
			di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...)
		case "CXXFLAGS":
			di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...)
		case "LDFLAGS":
			di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
		case "pkg-config":
			di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
		default:
			return fmt.Errorf("%s: invalid #cgo verb: %s", filename, sc.Text())
		}
	}
	return sc.Err()
}
Ejemplo n.º 9
0
func (w *PkgWalker) LookupObjects(conf *PkgConfig, cursor *FileCursor) {
	var cursorObj types.Object
	var cursorSelection *types.Selection
	var cursorObjIsDef bool
	//lookup defs

	var pkg *types.Package
	var pkgInfo *types.Info
	if cursor.xtest {
		pkgInfo = conf.XInfo
		pkg = conf.XPkg
	} else {
		pkgInfo = conf.Info
		pkg = conf.Pkg
	}

	_ = cursorObjIsDef
	if cursorObj == nil {
		for sel, obj := range pkgInfo.Selections {
			if cursor.pos >= sel.Sel.Pos() && cursor.pos <= sel.Sel.End() {
				cursorObj = obj.Obj()
				cursorSelection = obj
				break
			}
		}
	}
	if cursorObj == nil {
		for id, obj := range pkgInfo.Defs {
			if cursor.pos >= id.Pos() && cursor.pos <= id.End() {
				cursorObj = obj
				cursorObjIsDef = true
				break
			}
		}
	}
	_ = cursorSelection
	if cursorObj == nil {
		for id, obj := range pkgInfo.Uses {
			if cursor.pos >= id.Pos() && cursor.pos <= id.End() {
				cursorObj = obj
				break
			}
		}
	}
	if cursorObj == nil {
		return
	}

	kind, err := parserObjKind(cursorObj)
	if err != nil {
		log.Fatalln(err)
	}

	if kind == ObjField {
		if cursorObj.(*types.Var).Anonymous() {
			typ := orgType(cursorObj.Type())
			if named, ok := typ.(*types.Named); ok {
				cursorObj = named.Obj()
			}
		}
	}
	cursorPkg := cursorObj.Pkg()
	cursorPos := cursorObj.Pos()
	//var fieldTypeInfo *types.Info
	var fieldTypeObj types.Object
	//	if cursorPkg == pkg {
	//		fieldTypeInfo = pkgInfo
	//	}
	cursorIsInterfaceMethod := false
	var cursorInterfaceTypeName string

	if kind == ObjMethod && cursorSelection != nil && cursorSelection.Recv() != nil {
		sig := cursorObj.(*types.Func).Type().Underlying().(*types.Signature)
		if _, ok := sig.Recv().Type().Underlying().(*types.Interface); ok {
			if named, ok := cursorSelection.Recv().(*types.Named); ok {
				obj, typ := w.lookupNamedMethod(named, cursorObj.Name())
				if obj != nil {
					cursorObj = obj
				}
				if typ != nil {
					cursorPkg = typ.Obj().Pkg()
					cursorInterfaceTypeName = typ.Obj().Name()
				}
				cursorIsInterfaceMethod = true
			}
		}
	} else if kind == ObjField && cursorSelection != nil {
		if recv := cursorSelection.Recv(); recv != nil {
			typ := orgType(recv)
			if typ != nil {
				if name, ok := typ.(*types.Named); ok {
					fieldTypeObj = name.Obj()
					na := w.lookupNamedField(name, cursorObj.Name())
					if na != nil {
						fieldTypeObj = na.Obj()
					}
				}
			}
		}
	}
	if cursorPkg != nil && cursorPkg != pkg &&
		kind != ObjPkgName && w.isBinaryPkg(cursorPkg.Path()) {
		conf := &PkgConfig{
			IgnoreFuncBodies: true,
			AllowBinary:      true,
			WithTestFiles:    true,
			Info: &types.Info{
				Defs: make(map[*ast.Ident]types.Object),
			},
		}
		pkg, _ := w.Import("", cursorPkg.Path(), conf)
		if pkg != nil {
			if cursorIsInterfaceMethod {
				for _, obj := range conf.Info.Defs {
					if obj == nil {
						continue
					}
					if fn, ok := obj.(*types.Func); ok {
						if fn.Name() == cursorObj.Name() {
							if sig, ok := fn.Type().Underlying().(*types.Signature); ok {
								if named, ok := sig.Recv().Type().(*types.Named); ok {
									if named.Obj() != nil && named.Obj().Name() == cursorInterfaceTypeName {
										cursorPos = obj.Pos()
										break
									}
								}
							}
						}
					}
				}
			} else if kind == ObjField && fieldTypeObj != nil {
				for _, obj := range conf.Info.Defs {
					if obj == nil {
						continue
					}
					if _, ok := obj.(*types.TypeName); ok {
						if IsSameObject(fieldTypeObj, obj) {
							if t, ok := obj.Type().Underlying().(*types.Struct); ok {
								for i := 0; i < t.NumFields(); i++ {
									if t.Field(i).Id() == cursorObj.Id() {
										cursorPos = t.Field(i).Pos()
										break
									}
								}
							}
							break
						}
					}
				}
			} else {
				for k, v := range conf.Info.Defs {
					if k != nil && v != nil && IsSameObject(v, cursorObj) {
						cursorPos = k.Pos()
						break
					}
				}
			}
		}
		//		if kind == ObjField || cursorIsInterfaceMethod {
		//			fieldTypeInfo = conf.Info
		//		}
	}
	//	if kind == ObjField {
	//		fieldTypeObj = w.LookupStructFromField(fieldTypeInfo, cursorPkg, cursorObj, cursorPos)
	//	}
	if typesFindDef {
		fmt.Println(w.fset.Position(cursorPos))
	}
	if typesFindInfo {
		if kind == ObjField && fieldTypeObj != nil {
			typeName := fieldTypeObj.Name()
			if fieldTypeObj.Pkg() != nil && fieldTypeObj.Pkg() != pkg {
				typeName = fieldTypeObj.Pkg().Name() + "." + fieldTypeObj.Name()
			}
			fmt.Println(typeName, simpleObjInfo(cursorObj))
		} else if kind == ObjBuiltin {
			fmt.Println(builtinInfo(cursorObj.Name()))
		} else if kind == ObjPkgName {
			fmt.Println(cursorObj.String())
		} else if cursorIsInterfaceMethod {
			fmt.Println(strings.Replace(simpleObjInfo(cursorObj), "(interface)", cursorPkg.Name()+"."+cursorInterfaceTypeName, 1))
		} else {
			fmt.Println(simpleObjInfo(cursorObj))
		}
	}

	if typesFindDoc && typesFindDef {
		pos := w.fset.Position(cursorPos)
		file := w.parsedFileCache[pos.Filename]
		if file != nil {
			line := pos.Line
			var group *ast.CommentGroup
			for _, v := range file.Comments {
				lastLine := w.fset.Position(v.End()).Line
				if lastLine == line || lastLine == line-1 {
					group = v
				} else if lastLine > line {
					break
				}
			}
			if group != nil {
				fmt.Println(group.Text())
			}
		}
	}
	if !typesFindUse {
		return
	}

	var usages []int
	if kind == ObjPkgName {
		for id, obj := range pkgInfo.Uses {
			if obj != nil && obj.Id() == cursorObj.Id() { //!= nil && cursorObj.Pos() == obj.Pos() {
				usages = append(usages, int(id.Pos()))
			}
		}
	} else {
		//		for id, obj := range pkgInfo.Defs {
		//			if obj == cursorObj { //!= nil && cursorObj.Pos() == obj.Pos() {
		//				usages = append(usages, int(id.Pos()))
		//			}
		//		}
		for id, obj := range pkgInfo.Uses {
			if obj == cursorObj { //!= nil && cursorObj.Pos() == obj.Pos() {
				usages = append(usages, int(id.Pos()))
			}
		}
	}
	var pkg_path string
	var xpkg_path string
	if conf.Pkg != nil {
		pkg_path = conf.Pkg.Path()
	}
	if conf.XPkg != nil {
		xpkg_path = conf.XPkg.Path()
	}

	if cursorPkg != nil &&
		(cursorPkg.Path() == pkg_path || cursorPkg.Path() == xpkg_path) &&
		kind != ObjPkgName {
		usages = append(usages, int(cursorPos))
	}

	(sort.IntSlice(usages)).Sort()
	for _, pos := range usages {
		fmt.Println(w.fset.Position(token.Pos(pos)))
	}
	//check look for current pkg.object on pkg_test
	if typesFindUseAll || IsSamePkg(cursorPkg, conf.Pkg) {
		var addInfo *types.Info
		if conf.Cursor.xtest {
			addInfo = conf.Info
		} else {
			addInfo = conf.XInfo
		}
		if addInfo != nil && cursorPkg != nil {
			var usages []int
			//		for id, obj := range addInfo.Defs {
			//			if id != nil && obj != nil && obj.Id() == cursorObj.Id() {
			//				usages = append(usages, int(id.Pos()))
			//			}
			//		}
			for k, v := range addInfo.Uses {
				if k != nil && v != nil && IsSameObject(v, cursorObj) {
					usages = append(usages, int(k.Pos()))
				}
			}
			(sort.IntSlice(usages)).Sort()
			for _, pos := range usages {
				fmt.Println(w.fset.Position(token.Pos(pos)))
			}
		}
	}
	if !typesFindUseAll {
		return
	}

	if cursorPkg == nil {
		return
	}

	var find_def_pkg string
	var uses_paths []string
	if cursorPkg.Path() != pkg_path && cursorPkg.Path() != xpkg_path {
		find_def_pkg = cursorPkg.Path()
		uses_paths = append(uses_paths, cursorPkg.Path())
	}

	buildutil.ForEachPackage(&build.Default, func(importPath string, err error) {
		if err != nil {
			return
		}
		if importPath == conf.Pkg.Path() {
			return
		}
		bp, err := w.importPath(importPath, 0)
		if err != nil {
			return
		}
		find := false
		if bp.ImportPath == cursorPkg.Path() {
			find = true
		} else {
			for _, v := range bp.Imports {
				if v == cursorObj.Pkg().Path() {
					find = true
					break
				}
			}
		}
		if find {
			for _, v := range uses_paths {
				if v == bp.ImportPath {
					return
				}
			}
			uses_paths = append(uses_paths, bp.ImportPath)
		}
	})

	w.imported = make(map[string]*types.Package)
	for _, v := range uses_paths {
		conf := &PkgConfig{
			IgnoreFuncBodies: false,
			AllowBinary:      true,
			WithTestFiles:    true,
			Info: &types.Info{
				Uses: make(map[*ast.Ident]types.Object),
			},
			XInfo: &types.Info{
				Uses: make(map[*ast.Ident]types.Object),
			},
		}
		w.imported[v] = nil
		var usages []int
		vpkg, _ := w.Import("", v, conf)
		if vpkg != nil && vpkg != pkg {
			if conf.Info != nil {
				for k, v := range conf.Info.Uses {
					if k != nil && v != nil && IsSameObject(v, cursorObj) {
						usages = append(usages, int(k.Pos()))
					}
				}
			}
			if conf.XInfo != nil {
				for k, v := range conf.XInfo.Uses {
					if k != nil && v != nil && IsSameObject(v, cursorObj) {
						usages = append(usages, int(k.Pos()))
					}
				}
			}
		}
		if v == find_def_pkg {
			usages = append(usages, int(cursorPos))
		}
		(sort.IntSlice(usages)).Sort()
		for _, pos := range usages {
			fmt.Println(w.fset.Position(token.Pos(pos)))
		}
	}
}