Example #1
0
func stripParens(x ast.Expr) ast.Expr {
	if px, strip := x.(*ast.ParenExpr); strip {
		// parentheses must not be stripped if there are any
		// unparenthesized composite literals starting with
		// a type name
		ast.Inspect(px.X, func(node ast.Node) bool {
			switch x := node.(type) {
			case *ast.ParenExpr:
				// parentheses protect enclosed composite literals
				return false
			case *ast.CompositeLit:
				if isTypeName(x.Type) {
					strip = false // do not strip parentheses
				}
				return false
			}
			// in all other cases, keep inspecting
			return true
		})
		if strip {
			return stripParens(px.X)
		}
	}
	return x
}
Example #2
0
func lookup(filepath string, offset int) (Definition, error) {
	def := Definition{}

	f, err := parser.ParseFile(fileset, filepath, nil, 0, getScope(filepath))
	if err != nil {
		return def, err
	}

	containsOffset := func(node ast.Node) bool {
		from := fileset.Position(node.Pos()).Offset
		to := fileset.Position(node.End()).Offset
		return offset >= from && offset < to
	}

	// traverse the ast tree until we find a node at the given offset position
	var ident ast.Expr
	ast.Inspect(f, func(node ast.Node) bool {
		switch expr := node.(type) {
		case *ast.SelectorExpr:
			if containsOffset(expr) && containsOffset(expr.Sel) {
				ident = expr
			}
		case *ast.Ident:
			if containsOffset(expr) {
				ident = expr
			}
		}
		return ident == nil
	})

	if ident == nil {
		return def, errors.New("no identifier found")
	}

	pos := getDefPosition(ident)
	if pos == nil {
		return def, errors.New("could not find definition of identifier")
	}

	obj, _ := types.ExprType(ident, types.DefaultImporter)
	def.Name = obj.Name
	def.Position = *pos
	return def, nil
}
Example #3
0
func (def Definition) findReferences(searchpath string, recursive bool) (chan Reference, chan error) {
	refs := make(chan Reference)
	errs := make(chan error, 1000)

	// returns true on error and reports it
	failed := func(err error) bool {
		if err != nil {
			select {
			case errs <- err:
			default:
			}
			return true
		}
		return false
	}

	scanAST := func(f ast.Node) {
		check := func(expr ast.Expr) {
			pos := getDefPosition(expr)
			if pos != nil && *pos == def.Position {
				refs <- Reference{fileset.Position(expr.Pos())}
			}
		}

		ast.Inspect(f, func(node ast.Node) bool {
			switch e := node.(type) {
			case *ast.SelectorExpr:
				if e.Sel.Name == def.Name {
					check(e)
				}
			case *ast.Ident:
				if e.Name == def.Name {
					check(e)
				}
			}
			return true
		})
	}

	scanFile := func(filepath string) {
		defer func() {
			if e := recover(); e != nil {
				return
			}
		}()
		f, err := parser.ParseFile(fileset, filepath, nil, 0, getScope(filepath))
		if failed(err) {
			return
		}
		scanAST(f)
	}

	var scanFolder func(dirpath string)
	scanFolder = func(dirpath string) {
		filter := func(fi os.FileInfo) bool {
			return path.Ext(fi.Name()) == ".go"
		}
		defer func() {
			if e := recover(); e != nil {
				return
			}
		}()
		result, err := parser.ParseDir(fileset, dirpath, filter, 0)
		if failed(err) {
			return
		}

		for _, pkg := range result {
			scanAST(pkg)
		}

		if !recursive {
			return
		}

		dir, err := os.Open(dirpath)
		if failed(err) {
			return
		}

		infos, err := dir.Readdir(0)
		if failed(err) {
			return
		}

		for _, fi := range infos {
			if fi.IsDir() && !strings.HasPrefix(fi.Name(), ".") {
				scanFolder(path.Join(dirpath, fi.Name()))
			}
		}
	}

	go func() {
		defer close(refs)
		defer close(errs)

		fi, err := os.Lstat(searchpath)
		if err != nil {
			return
		}
		if fi.IsDir() {
			scanFolder(searchpath)
		} else {
			scanFile(searchpath)
		}
	}()

	return refs, errs
}