Esempio n. 1
0
// ParseQueryPos parses the source query position pos.
// If needExact, it must identify a single AST subtree.
//
func ParseQueryPos(imp *importer.Importer, pos string, needExact bool) (*QueryPos, error) {
	start, end, err := parseQueryPos(imp.Fset, pos)
	if err != nil {
		return nil, err
	}
	info, path, exact := imp.PathEnclosingInterval(start, end)
	if path == nil {
		return nil, fmt.Errorf("no syntax here")
	}
	if needExact && !exact {
		return nil, fmt.Errorf("ambiguous selection within %s", importer.NodeDescription(path[0]))
	}
	return &QueryPos{start, end, info, path}, nil
}
Esempio n. 2
0
// CreatePackages creates SSA Packages for all error-free packages
// loaded by the specified Importer.
//
// If all packages were error-free, it is safe to call
// prog.BuildAll(), and nil is returned.  Otherwise an error is
// returned.
//
func (prog *Program) CreatePackages(imp *importer.Importer) error {
	var errpkgs []string
	for _, info := range imp.AllPackages() {
		if info.Err != nil {
			errpkgs = append(errpkgs, info.Pkg.Path())
		} else {
			prog.CreatePackage(info)
		}
	}
	if errpkgs != nil {
		return fmt.Errorf("couldn't create these SSA packages due to type errors: %s",
			strings.Join(errpkgs, ", "))
	}
	return nil
}
Esempio n. 3
0
// ParseQueryPos parses the source query position pos.
// If needExact, it must identify a single AST subtree;
// this is appropriate for queries that allow fairly arbitrary syntax,
// e.g. "describe".
//
func ParseQueryPos(imp *importer.Importer, posFlag string, needExact bool) (*QueryPos, error) {
	filename, startOffset, endOffset, err := parsePosFlag(posFlag)
	if err != nil {
		return nil, err
	}
	start, end, err := findQueryPos(imp.Fset, filename, startOffset, endOffset)
	if err != nil {
		return nil, err
	}
	info, path, exact := imp.PathEnclosingInterval(start, end)
	if path == nil {
		return nil, fmt.Errorf("no syntax here")
	}
	if needExact && !exact {
		return nil, fmt.Errorf("ambiguous selection within %s", astutil.NodeDescription(path[0]))
	}
	return &QueryPos{imp.Fset, start, end, path, exact, info}, nil
}
Esempio n. 4
0
func newOracle(imp *importer.Importer, args []string, ptalog io.Writer, needs int, reflection bool) (*Oracle, error) {
	o := &Oracle{fset: imp.Fset}

	// Load/parse/type-check program from args.
	initialPkgInfos, args, err := imp.LoadInitialPackages(args)
	if err != nil {
		return nil, err // I/O or parser error
	}
	if len(args) > 0 {
		return nil, fmt.Errorf("surplus arguments: %q", args)
	}

	// Retain type info for all ASTs in the program.
	if needs&needRetainTypeInfo != 0 {
		m := make(map[*types.Package]*importer.PackageInfo)
		for _, p := range imp.AllPackages() {
			m[p.Pkg] = p
		}
		o.typeInfo = m
	}

	// Create SSA package for the initial packages and their dependencies.
	if needs&needSSA != 0 {
		prog := ssa.NewProgram(o.fset, 0)

		// Create SSA packages.
		if err := prog.CreatePackages(imp); err != nil {
			return nil, err
		}

		// For each initial package (specified on the command line),
		// if it has a main function, analyze that,
		// otherwise analyze its tests, if any.
		var testPkgs, mains []*ssa.Package
		for _, info := range initialPkgInfos {
			initialPkg := prog.Package(info.Pkg)

			// Add package to the pointer analysis scope.
			if initialPkg.Func("main") != nil {
				mains = append(mains, initialPkg)
			} else {
				testPkgs = append(testPkgs, initialPkg)
			}
		}
		if testPkgs != nil {
			if p := prog.CreateTestMainPackage(testPkgs...); p != nil {
				mains = append(mains, p)
			}
		}
		if mains == nil {
			return nil, fmt.Errorf("analysis scope has no main and no tests")
		}
		o.ptaConfig.Log = ptalog
		o.ptaConfig.Reflection = reflection
		o.ptaConfig.Mains = mains

		if needs&needSSADebug != 0 {
			for _, pkg := range prog.AllPackages() {
				pkg.SetDebugMode(true)
			}
		}

		o.prog = prog
	}

	return o, nil
}
Esempio n. 5
0
func newOracle(imp *importer.Importer, args []string, ptalog io.Writer, needs int, reflection bool) (*Oracle, error) {
	o := &Oracle{
		prog:   ssa.NewProgram(imp.Fset, 0),
		timers: make(map[string]time.Duration),
	}
	o.config.Log = ptalog
	o.config.Reflection = reflection

	// Load/parse/type-check program from args.
	start := time.Now()
	initialPkgInfos, args, err := imp.LoadInitialPackages(args)
	if err != nil {
		return nil, err // I/O or parser error
	}
	if len(args) > 0 {
		return nil, fmt.Errorf("surplus arguments: %q", args)
	}
	o.timers["load/parse/type"] = time.Since(start)

	// Retain type info for all ASTs in the program.
	if needs&needAllTypeInfo != 0 {
		m := make(map[*types.Package]*importer.PackageInfo)
		for _, p := range imp.AllPackages() {
			m[p.Pkg] = p
		}
		o.typeInfo = m
	}

	// Create SSA package for the initial package and its dependencies.
	if needs&needSSA != 0 {
		start = time.Now()

		// Create SSA packages.
		if err := o.prog.CreatePackages(imp); err != nil {
			return nil, err
		}

		// Initial packages (specified on command line)
		for _, info := range initialPkgInfos {
			initialPkg := o.prog.Package(info.Pkg)

			// Add package to the pointer analysis scope.
			if initialPkg.Func("main") == nil {
				// TODO(adonovan): to simulate 'go test' more faithfully, we
				// should build a single synthetic testmain package,
				// not synthetic main functions to many packages.
				if initialPkg.CreateTestMainFunction() == nil {
					return nil, fmt.Errorf("analysis scope has no main() entry points")
				}
			}
			o.config.Mains = append(o.config.Mains, initialPkg)
		}

		if needs&needSSADebug != 0 {
			for _, pkg := range o.prog.AllPackages() {
				pkg.SetDebugMode(true)
			}
		}

		o.timers["SSA-create"] = time.Since(start)
	}

	return o, nil
}