Repository: goplus/gop
Pull request #1603 (2024-01-07 12:55:31)

Load abs


Patch:
diff --git a/imp.go b/imp.go
index 9a68db7f..287bbcc3 100644
--- a/imp.go
+++ b/imp.go
@@ -44,8 +44,11 @@ func NewImporter(mod *gopmod.Module, gop *env.Gop, fset *token.FileSet) *Importe
 	const (
 		defaultFlags = GenFlagPrompt | GenFlagPrintError
 	)
+	if mod == nil {
+		mod = gopmod.Default
+	}
 	dir := ""
-	if mod.IsValid() {
+	if hasModule(mod) {
 		dir = mod.Root()
 	}
 	impFrom := packages.NewImporter(fset, dir)
@@ -67,7 +70,7 @@ func (p *Importer) Import(pkgPath string) (pkg *types.Package, err error) {
 			return p.impFrom.ImportFrom(pkgPath, gopRoot, 0)
 		}
 	}
-	if mod := p.mod; mod.IsValid() {
+	if mod := p.mod; hasModule(mod) {
 		ret, e := mod.Lookup(pkgPath)
 		if e != nil {
 			return nil, e
diff --git a/load.go b/load.go
index 58567d10..7c47a546 100644
--- a/load.go
+++ b/load.go
@@ -140,6 +140,11 @@ func LoadMod(dir string) (mod *gopmod.Module, err error) {
 	return gopmod.Default, nil
 }
 
+func hasModule(mod *gopmod.Module) bool {
+	f := mod.File
+	return f != nil && f.Syntax != nil
+}
+
 // -----------------------------------------------------------------------------
 
 func LoadDir(dir string, conf *Config, genTestPkg bool, promptGenGo ...bool) (out, test *gox.Package, err error) {
@@ -158,7 +163,7 @@ func LoadDir(dir string, conf *Config, genTestPkg bool, promptGenGo ...bool) (ou
 	pkgs, err := parser.ParseDirEx(fset, dir, parser.Config{
 		ClassKind: mod.ClassKind,
 		Filter:    conf.Filter,
-		Mode:      parser.ParseComments,
+		Mode:      parser.ParseComments | parser.SaveAbsFile,
 	})
 	if err != nil {
 		return
@@ -178,13 +183,11 @@ func LoadDir(dir string, conf *Config, genTestPkg bool, promptGenGo ...bool) (ou
 
 	var pkgTest *ast.Package
 	var clConf = &cl.Config{
-		Fset:        fset,
-		Importer:    imp,
-		LookupClass: mod.LookupClass,
-		LookupPub:   c2go.LookupPub(mod),
-	}
-	if mod.IsValid() {
-		clConf.RelativeBase = mod.Root()
+		Fset:         fset,
+		RelativeBase: relativeBaseOf(mod),
+		Importer:     imp,
+		LookupClass:  mod.LookupClass,
+		LookupPub:    c2go.LookupPub(mod),
 	}
 
 	for name, pkg := range pkgs {
@@ -221,6 +224,14 @@ func LoadDir(dir string, conf *Config, genTestPkg bool, promptGenGo ...bool) (ou
 	return
 }
 
+func relativeBaseOf(mod *gopmod.Module) string {
+	if hasModule(mod) {
+		return mod.Root()
+	}
+	dir, _ := os.Getwd()
+	return dir
+}
+
 // -----------------------------------------------------------------------------
 
 func LoadFiles(dir string, files []string, conf *Config) (out *gox.Package, err error) {
@@ -237,7 +248,7 @@ func LoadFiles(dir string, files []string, conf *Config) (out *gox.Package, err
 	if fset == nil {
 		fset = token.NewFileSet()
 	}
-	pkgs, err := parser.ParseFiles(fset, files, parser.ParseComments)
+	pkgs, err := parser.ParseFiles(fset, files, parser.ParseComments|parser.SaveAbsFile)
 	if err != nil {
 		err = errors.NewWith(err, `parser.ParseFiles(fset, files, parser.ParseComments)`, -2, "parser.ParseFiles", fset, files, parser.ParseComments)
 		return
@@ -256,10 +267,11 @@ func LoadFiles(dir string, files []string, conf *Config) (out *gox.Package, err
 			imp = NewImporter(mod, gop, fset)
 		}
 		clConf := &cl.Config{
-			Fset:        fset,
-			Importer:    imp,
-			LookupClass: mod.LookupClass,
-			LookupPub:   c2go.LookupPub(mod),
+			Fset:         fset,
+			RelativeBase: relativeBaseOf(mod),
+			Importer:     imp,
+			LookupClass:  mod.LookupClass,
+			LookupPub:    c2go.LookupPub(mod),
 		}
 		out, err = cl.NewPackage("", pkg, clConf)
 		if err != nil {
diff --git a/parser/fsx/fsys.go b/parser/fsx/fsys.go
index 013b16e5..d2f1fde1 100644
--- a/parser/fsx/fsys.go
+++ b/parser/fsx/fsys.go
@@ -35,6 +35,9 @@ type FileSystem interface {
 	// If the path is empty, Base returns ".".
 	// If the path consists entirely of separators, Base returns a single separator.
 	Base(filename string) string
+
+	// Abs returns an absolute representation of path.
+	Abs(path string) (string, error)
 }
 
 // -----------------------------------------------------------------------------
@@ -61,6 +64,11 @@ func (p localFS) Base(filename string) string {
 	return filepath.Base(filename)
 }
 
+// Abs returns an absolute representation of path.
+func (p localFS) Abs(path string) (string, error) {
+	return filepath.Abs(path)
+}
+
 var Local FileSystem = localFS{}
 
 // -----------------------------------------------------------------------------
diff --git a/parser/fsx/memfs/fs.go b/parser/fsx/memfs/fs.go
index 0721f20f..8a076fc1 100644
--- a/parser/fsx/memfs/fs.go
+++ b/parser/fsx/memfs/fs.go
@@ -80,6 +80,10 @@ func (p *FileFS) Base(filename string) string {
 	return filepath.Base(filename)
 }
 
+func (p *FileFS) Abs(path string) (string, error) {
+	return path, nil
+}
+
 func readSource(src interface{}) ([]byte, error) {
 	switch s := src.(type) {
 	case string:
diff --git a/parser/fsx/memfs/memfs.go b/parser/fsx/memfs/memfs.go
index 4b62ee33..75de1f6c 100644
--- a/parser/fsx/memfs/memfs.go
+++ b/parser/fsx/memfs/memfs.go
@@ -117,6 +117,10 @@ func (p *FS) Base(filename string) string {
 	return path.Base(filename)
 }
 
+func (p *FS) Abs(path string) (string, error) {
+	return path, nil
+}
+
 // -----------------------------------------------------------------------------
 
 // SingleFile creates a file system that only contains a single file.
diff --git a/parser/interface.go b/parser/interface.go
index 0744bdc9..d9cff8e0 100644
--- a/parser/interface.go
+++ b/parser/interface.go
@@ -49,6 +49,8 @@ const (
 	ParseGoAsGoPlus Mode = 1 << 16
 	// ParserGoPlusClass - parse Go+ classfile by gop/parser
 	ParseGoPlusClass Mode = 1 << 17
+	// SaveAbsFile - parse and save absolute path to pkg.Files
+	SaveAbsFile Mode = 1 << 18
 )
 
 // -----------------------------------------------------------------------------
diff --git a/parser/parser_gop.go b/parser/parser_gop.go
index 44adb4a1..0b76a19e 100644
--- a/parser/parser_gop.go
+++ b/parser/parser_gop.go
@@ -115,6 +115,10 @@ func ParseEntry(fset *token.FileSet, filename string, src interface{}, conf Conf
 // returned. If a parse error occurred, a non-nil but incomplete map and the
 // first error encountered are returned.
 func ParseFSDir(fset *token.FileSet, fs FileSystem, dir string, conf Config) (pkgs map[string]*ast.Package, first error) {
+	if conf.Mode&SaveAbsFile != 0 {
+		dir, _ = fs.Abs(dir)
+		conf.Mode &^= SaveAbsFile
+	}
 	list, err := fs.ReadDir(dir)
 	if err != nil {
 		return nil, err
@@ -300,6 +304,9 @@ func ParseFSFile(fset *token.FileSet, fs FileSystem, filename string, src interf
 	if err != nil {
 		return
 	}
+	if mode&SaveAbsFile != 0 {
+		filename, _ = fs.Abs(filename)
+	}
 	return parseFile(fset, filename, code, mode)
 }
 


Test patch:
diff --git a/parser/parserdir_test.go b/parser/parserdir_test.go
index f4da4c60..ff925701 100644
--- a/parser/parserdir_test.go
+++ b/parser/parserdir_test.go
@@ -194,6 +194,40 @@ func TestParseEntry(t *testing.T) {
 	})
 }
 
+func TestSaveAbsFile(t *testing.T) {
+	fset := token.NewFileSet()
+	src, err := os.ReadFile("./_testdata/functype/functype.go")
+	if err != nil {
+		t.Fatal("os.ReadFile:", err)
+	}
+	conf := Config{}
+	conf.Mode = SaveAbsFile
+	t.Run(".gop file", func(t *testing.T) {
+		f, err := ParseEntry(fset, "./functype.gop", src, conf)
+		if err != nil {
+			t.Fatal("ParseEntry failed:", err)
+		}
+		if f.IsClass || f.IsProj || f.IsNormalGox {
+			t.Fatal("ParseEntry functype.gop:", f.IsClass, f.IsProj, f.IsNormalGox)
+		}
+	})
+	t.Run(".gop file", func(t *testing.T) {
+		f, err := ParseFile(fset, "./functype.gop", src, conf.Mode)
+		if err != nil {
+			t.Fatal("ParseEntry failed:", err)
+		}
+		if f.IsClass || f.IsProj || f.IsNormalGox {
+			t.Fatal("ParseEntry functype.gop:", f.IsClass, f.IsProj, f.IsNormalGox)
+		}
+	})
+	t.Run("dir", func(t *testing.T) {
+		_, err := ParseDirEx(fset, "./_nofmt/cmdlinestyle1", conf)
+		if err != nil {
+			t.Fatal("ParseDirEx failed:", err)
+		}
+	})
+}
+
 func TestGopAutoGen(t *testing.T) {
 	fset := token.NewFileSet()
 	fs := memfs.SingleFile("/foo", "gop_autogen.go", ``)