@@ -100,11 +100,31 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
100
100
dir = filepath .Clean (dir )
101
101
}
102
102
103
+ // golang.org/issue/32917: We should resolve a relative path to a
104
+ // package path only if the relative path actually contains the code
105
+ // for that package.
106
+ if ! dirContainsPackage (dir ) {
107
+ // If we're outside of a module, ensure that the failure mode
108
+ // indicates that.
109
+ ModRoot ()
110
+
111
+ // If the directory is local but does not exist, don't return it
112
+ // while loader is iterating, since this might trigger a fetch.
113
+ // After loader is done iterating, we still need to return the
114
+ // path, so that "go list -e" produces valid output.
115
+ if ! iterating {
116
+ // We don't have a valid path to resolve to, so report the
117
+ // unresolved path.
118
+ m .Pkgs = append (m .Pkgs , pkg )
119
+ }
120
+ continue
121
+ }
122
+
103
123
// Note: The checks for @ here are just to avoid misinterpreting
104
124
// the module cache directories (formerly GOPATH/src/mod/[email protected] /bar).
105
125
// It's not strictly necessary but helpful to keep the checks.
106
126
if modRoot != "" && dir == modRoot {
107
- pkg = Target . Path
127
+ pkg = targetPrefix
108
128
} else if modRoot != "" && strings .HasPrefix (dir , modRoot + string (filepath .Separator )) && ! strings .Contains (dir [len (modRoot ):], "@" ) {
109
129
suffix := filepath .ToSlash (dir [len (modRoot ):])
110
130
if strings .HasPrefix (suffix , "/vendor/" ) {
@@ -121,7 +141,13 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
121
141
continue
122
142
}
123
143
} else {
124
- pkg = Target .Path + suffix
144
+ modPkg := targetPrefix + suffix
145
+ if _ , ok := dirInModule (modPkg , targetPrefix , modRoot , true ); ok {
146
+ pkg = modPkg
147
+ } else if ! iterating {
148
+ ModRoot ()
149
+ base .Errorf ("go: directory %s is outside main module" , base .ShortPath (dir ))
150
+ }
125
151
}
126
152
} else if sub := search .InDir (dir , cfg .GOROOTsrc ); sub != "" && sub != "." && ! strings .Contains (sub , "@" ) {
127
153
pkg = filepath .ToSlash (sub )
@@ -134,16 +160,6 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
134
160
base .Errorf ("go: directory %s outside available modules" , base .ShortPath (dir ))
135
161
}
136
162
}
137
- info , err := os .Stat (dir )
138
- if err != nil || ! info .IsDir () {
139
- // If the directory is local but does not exist, don't return it
140
- // while loader is iterating, since this would trigger a fetch.
141
- // After loader is done iterating, we still need to return the
142
- // path, so that "go list -e" produces valid output.
143
- if iterating {
144
- continue
145
- }
146
- }
147
163
m .Pkgs = append (m .Pkgs , pkg )
148
164
}
149
165
@@ -247,6 +263,32 @@ func pathInModuleCache(dir string) string {
247
263
return ""
248
264
}
249
265
266
+ var dirContainsPackageCache sync.Map // absolute dir → bool
267
+
268
+ func dirContainsPackage (dir string ) bool {
269
+ isPkg , ok := dirContainsPackageCache .Load (dir )
270
+ if ! ok {
271
+ _ , err := cfg .BuildContext .ImportDir (dir , 0 )
272
+ if err == nil {
273
+ isPkg = true
274
+ } else {
275
+ if fi , statErr := os .Stat (dir ); statErr != nil || ! fi .IsDir () {
276
+ // A non-directory or inaccessible directory is not a Go package.
277
+ isPkg = false
278
+ } else if _ , noGo := err .(* build.NoGoError ); noGo {
279
+ // A directory containing no Go source files is not a Go package.
280
+ isPkg = false
281
+ } else {
282
+ // An error other than *build.NoGoError indicates that the package exists
283
+ // but has some other problem (such as a syntax error).
284
+ isPkg = true
285
+ }
286
+ }
287
+ isPkg , _ = dirContainsPackageCache .LoadOrStore (dir , isPkg )
288
+ }
289
+ return isPkg .(bool )
290
+ }
291
+
250
292
// ImportFromFiles adds modules to the build list as needed
251
293
// to satisfy the imports in the named Go source files.
252
294
func ImportFromFiles (gofiles []string ) {
0 commit comments