Beispiel #1
0
func getSourceFiles(pkgPath string, deep bool) ([]string, error) {
	pkgDir, err := os.Open(pkgPath)
	if err != nil {
		util.Err("error while opening package at path [%s]\n%v", pkgPath, err)
		return nil, err
	}

	filesInfos, err := pkgDir.Readdir(0)
	if err != nil {
		util.Err("error reading opening package at path [%s]\n%v", pkgPath, err)
		return nil, err
	}

	var files []string
	for _, f := range filesInfos {
		if f.IsDir() && deep && isValidSourceDir(f.Name()) {
			util.Debug("append folder [%s]", f.Name())
			dirFiles, err := getSourceFiles(pkgPath+"/"+f.Name(), true)
			if err != nil {
				return dirFiles, err
			}
			files = append(files, dirFiles...)
		} else if isValidSourceFile(f.Name()) {
			util.Debug("append file [%s]", f.Name())
			if strings.HasSuffix(f.Name(), "_test.go") {
				files = append(files, pkgPath+"/"+f.Name())
			} else {
				files = append([]string{pkgPath + "/" + f.Name()}, files...)
			}
		}
	}
	util.Info("FILES [%v]", files)

	return files, nil
}
Beispiel #2
0
func addInterface(obj types.Object, ident *ast.Ident, ctx *getDefinitionsContext) {
	interfac := obj.Type().Underlying().(*types.Interface)

	def := createDef(obj, ident, ctx, true)
	updateGetDefinitionsContext(ctx, def, ident, obj)

	util.Debug("adding interface [%s] [%v] [%v] [%v]", def.Name, def.Pkg, obj.Type().Underlying(), obj.Type())
	//Adding all methods of interface
	for i := 0; i < interfac.NumMethods(); i++ {
		f := interfac.Method(i)
		def := createDef(f, nil, ctx, false)
		util.Debug("\tadding method [%v] [%s]", f, def.Name)
		updateGetDefinitionsContext(ctx, def, ident, f)
	}
}
Beispiel #3
0
//Collect going through package and collect info
//using conf.Check method. It's using this implementation
//of importer for check all inner packages and go/types/importer.Default()
//to check all built in packages (without sources)
func (_importer *CollectInfoImporter) Collect() (*types.Package, *token.FileSet, error) {
	var conf types.Config
	conf.Importer = _importer
	conf.Error = _importer.errorHandler

	if _importer.packages == nil {
		_importer.packages = make(map[string]*types.Package)
	}

	var pkg *types.Package
	var err error
	var files []string

	if files, err = fs.SourceFiles(_importer.Pkg, false); err != nil {
		return nil, nil, err
	}
	if _importer.fset, _importer.astFiles, err = doParseFiles(files, _importer.fset); err != nil {
		return nil, nil, err
	}

	//XXX: return positive result if check() returns error.
	pkg, _ = conf.Check(_importer.Pkg, _importer.fset, _importer.astFiles, _importer.Info)
	// if pkg, err = conf.Check(_importer.Pkg, _importer.fset, _importer.astFiles, _importer.Info); err != nil {
	// 	return pkg, _importer.fset, err
	// }

	_importer.packages[_importer.Pkg] = pkg
	util.Debug("package [%s] successfully parsed\n", pkg.Name())

	return pkg, _importer.fset, nil
}
Beispiel #4
0
func doParseFiles(filePathes []string, fset *token.FileSet) (*token.FileSet, []*ast.File, error) {
	if fset == nil {
		fset = token.NewFileSet()
	}
	util.Info("parsing files %v", filePathes)
	astFiles := make([]*ast.File, 0, len(filePathes))
	for _, f := range filePathes {
		//XXX: Ignoring files with packages ends with _test.
		//XXX: Doing that because getting error in check()
		//XXX: cause source file is still going to current
		//XXX: packages. Need to analyze package before
		//XXX: and check both packages separately.
		tempFset := token.NewFileSet()
		astFile, err := parser.ParseFile(tempFset, f, nil, 0)
		if !strings.HasSuffix(astFile.Name.Name, "_test") {
			if err != nil {
				return nil, nil, err
			}
			astFile, _ := parser.ParseFile(fset, f, nil, 0)
			astFiles = append(astFiles, astFile)
		}
	}

	iterateFunc := func(f *token.File) bool {
		util.Debug("\t%s", f.Name())
		return true
	}
	fset.Iterate(iterateFunc)
	return fset, astFiles, nil
}
Beispiel #5
0
func logType(t types.TypeAndValue) {
	if t.Type != nil {
		util.Debug("type [%s] [%s] [%s] [%s]", reflect.TypeOf(t.Type), t.Type.String(), reflect.TypeOf(t.Type.Underlying()), t.Type.Underlying().String())
		switch t.Type.(type) {
		case *types.Signature:
			s := t.Type.(*types.Signature)
			if s.Recv() != nil {
				util.Info("\t\t[%s] [%s]", s.Recv(), s.Recv().Type().String())
			}
			if tuple := s.Params(); tuple != nil {
				for i := 0; i < tuple.Len(); i++ {
					v := tuple.At(i)
					util.Debug("\t\t%s", v.Name())
					if types.IsInterface(v.Type()) {
						util.Debug("\t\t\t<------interface")
					}
				}
			}
		}
	}
}
Beispiel #6
0
func lookupMethod(def *Definition, iDef *Definition, ctx *getDefinitionsContext) *Definition {
	methodName := iDef.Name + "." + def.SimpleName
	externalInterfaceMethodName := "interface." + def.SimpleName
	def.InterfacesDefs = append(def.InterfacesDefs, iDef)
	if methodDef := ctx.defs[methodName]; methodDef != nil {
		return methodDef
	} else if methodDef := ctx.defs[externalInterfaceMethodName]; methodDef != nil {
		return methodDef
	} else {
		util.Debug("can't find method [%s]", methodName)
	}
	return nil
}
Beispiel #7
0
func isUsed(def *Definition) bool {
	used := true

	if len(def.Usages) == 0 {
		used = false
	} else {
		//Checking pathes of usages to not count internal
		hasExternalUsages := false
		util.Debug("checking [%s]", def.Name)
		for _, u := range def.Usages {
			pkgPath := ""
			if def.Pkg != nil {
				pkgPath = def.Pkg.Path()
			} else if dotIdx := strings.LastIndex(def.Name, "."); dotIdx >= 0 {
				pkgPath = def.Name[0:dotIdx]
			}
			util.Debug("checking [%v]", u.Pos)
			if u.Pos.IsValid() && fs.GetPackagePath(u.Pos.Filename) != pkgPath {
				hasExternalUsages = true
				break
			}
		}
		used = hasExternalUsages
	}

	if !used {
		//Check all interfaces
		for _, i := range def.Interfaces {
			if isUsed(i) {
				used = true
				break
			}
		}
	}
	return used
}
Beispiel #8
0
func implements(t types.Type, interfac *types.Interface, pkg *types.Package) bool {
	if interfac == nil || t == nil || interfac.Empty() {
		return false
	}
	if types.Implements(t, interfac) {
		return true
	}
	//For some reason, interfaces that comes
	//already built in (not from sources) are
	//not working with types.Implements method
	for i := 0; i < interfac.NumMethods(); i++ {
		m := interfac.Method(i)
		obj, _, _ := types.LookupFieldOrMethod(t, true, pkg, m.Name())
		if obj == nil {
			util.Debug("method %s not found in type %v", m.Name(), t)
			return false
		}
	}
	return true
}
Beispiel #9
0
func fillInterfaces(def *Definition, obj types.Object, ctx *getDefinitionsContext) {
	switch obj.(type) {
	case *types.TypeName:
		//Filling information about implemented
		//interfaces to type's definition.
		typ := obj.(*types.TypeName)
		if typ.Type() != nil {
			for _, di := range ctx.interfaces {
				if di.interfac != nil && di.def != nil && implements(typ.Type(), di.interfac, typ.Pkg()) {
					def.InterfacesDefs = append(def.InterfacesDefs, di.def)
				}
			}
		}
	case *types.Func:
		f := obj.(*types.Func)
		underlyingType := f.Type().Underlying()
		switch underlyingType.(type) {
		case *types.Signature:
			s := underlyingType.(*types.Signature)
			if s.Recv() != nil {
				//Getting all interfaces from function's receiver and
				//searching for current function in each interface.
				//If found, then adding method's definition to function's
				//interfaces
				recvTypeName := strings.Replace(s.Recv().Type().String(), "*", "", 1)
				if typeDef, ok := ctx.defs[recvTypeName]; ok {
					for _, iDef := range typeDef.InterfacesDefs {
						def.InterfacesDefs = append(def.InterfacesDefs, iDef)
						if methodDef := lookupMethod(def, iDef, ctx); methodDef != nil {
							def.InterfacesDefs = append(def.InterfacesDefs, methodDef)
						}
					}
				} else {
					util.Debug("recv type not found [%s]", s.Recv().Type().String())
				}
			}
		}
	}
}