Repository: goplus/gop
Pull request #1600 (2024-01-07 03:23:28)

load: use parser.ParseFileAbsolute

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/goplus/gop/pull/1600?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`56af4d2`)](https://app.codecov.io/gh/goplus/gop/commit/56af4d2bf7ad8c89f15cfc0e8a7cb4549791d3e7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus) 91.36% compared to head [(`b376ad5`)](https://app.codecov.io/gh/goplus/gop/pull/1600?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus) 91.35%.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1600      +/-   ##
==========================================
- Coverage   91.36%   91.35%   -0.02%     
==========================================
  Files          39       38       -1     
  Lines       10273    10271       -2     
==========================================
- Hits         9386     9383       -3     
- Misses        721      722       +1     
  Partials      166      166              
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/goplus/gop/pull/1600?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goplus).


Patch:
diff --git a/load.go b/load.go
index 6e363ffc..bc9df95e 100644
--- a/load.go
+++ b/load.go
@@ -168,10 +168,14 @@ func LoadDir(dir string, conf *Config, genTestPkg bool, promptGenGo ...bool) (ou
 		return
 	}
 
+	mode := parser.ParseComments
+	if mod.IsValid() {
+		mode |= parser.ParseFileAbsolute
+	}
 	pkgs, err := parser.ParseDirEx(fset, dir, parser.Config{
 		ClassKind: mod.ClassKind,
 		Filter:    conf.Filter,
-		Mode:      parser.ParseComments,
+		Mode:      mode,
 	})
 	if err != nil {
 		return
@@ -250,7 +254,11 @@ func LoadFiles(files []string, conf *Config) (out *gox.Package, err error) {
 		return
 	}
 
-	pkgs, err := parser.ParseFiles(fset, files, parser.ParseComments)
+	mode := parser.ParseComments
+	if mod.IsValid() {
+		mode |= parser.ParseFileAbsolute
+	}
+	pkgs, err := parser.ParseFiles(fset, files, mode)
 	if err != nil {
 		err = errors.NewWith(err, `parser.ParseFiles(fset, files, parser.ParseComments)`, -2, "parser.ParseFiles", fset, files, parser.ParseComments)
 		return
@@ -270,6 +278,9 @@ func LoadFiles(files []string, conf *Config) (out *gox.Package, err error) {
 			LookupClass: mod.LookupClass,
 			LookupPub:   c2go.LookupPub(mod),
 		}
+		if mod.IsValid() {
+			clConf.RelativeBase = mod.Root()
+		}
 		out, err = cl.NewPackage("", pkg, clConf)
 		if err != nil {
 			if conf.IgnoreNotatedError {
diff --git a/parser/interface.go b/parser/interface.go
index 0744bdc9..92ea2287 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
+	// ParseFileAbsolute - parse Go+ files to absolute path
+	ParseFileAbsolute Mode = 1 << 18
 )
 
 // -----------------------------------------------------------------------------
diff --git a/parser/parser_gop.go b/parser/parser_gop.go
index 44adb4a1..94bebae0 100644
--- a/parser/parser_gop.go
+++ b/parser/parser_gop.go
@@ -23,6 +23,7 @@ import (
 	"io/fs"
 	"os"
 	"path"
+	"path/filepath"
 	"strings"
 
 	goast "go/ast"
@@ -115,6 +116,11 @@ 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&ParseFileAbsolute != 0 && fs == fsx.Local {
+		if absDir, err := filepath.Abs(dir); err == nil {
+			dir = absDir
+		}
+	}
 	list, err := fs.ReadDir(dir)
 	if err != nil {
 		return nil, err
@@ -194,6 +200,11 @@ func ParseFSDir(fset *token.FileSet, fs FileSystem, dir string, conf Config) (pk
 // ParseFSEntry parses the source code of a single Go+ source file and returns the corresponding ast.File node.
 // Compared to ParseFSFile, ParseFSEntry detects fileKind by its filename.
 func ParseFSEntry(fset *token.FileSet, fs FileSystem, filename string, src interface{}, conf Config) (f *ast.File, err error) {
+	if conf.Mode&ParseFileAbsolute != 0 {
+		if abs, err := filepath.Abs(filename); err == nil {
+			filename = abs
+		}
+	}
 	fname := fs.Base(filename)
 	fnameRmGox := fname
 	ext := path.Ext(fname)
@@ -296,6 +307,11 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
 
 // ParseFSFile parses the source code of a single Go+ source file and returns the corresponding ast.File node.
 func ParseFSFile(fset *token.FileSet, fs FileSystem, filename string, src interface{}, mode Mode) (f *ast.File, err error) {
+	if mode&ParseFileAbsolute != 0 {
+		if abs, err := filepath.Abs(filename); err == nil {
+			filename = abs
+		}
+	}
 	code, err := readSourceFS(fs, filename, src)
 	if err != nil {
 		return


Test patch:
diff --git a/parser/parserdir_test.go b/parser/parserdir_test.go
index f4da4c60..46140b46 100644
--- a/parser/parserdir_test.go
+++ b/parser/parserdir_test.go
@@ -194,6 +194,40 @@ func TestParseEntry(t *testing.T) {
 	})
 }
 
+func TestParseFileAbsolute(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 = ParseFileAbsolute
+	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", ``)