@@ -11,6 +11,8 @@ import (
1111 "strings"
1212 "time"
1313
14+ "github.com/golangci/golangci-lint/pkg/logutils"
15+
1416 "github.com/golangci/go-tools/ssa"
1517 "github.com/golangci/go-tools/ssa/ssautil"
1618 "github.com/golangci/golangci-lint/pkg/config"
@@ -21,6 +23,8 @@ import (
2123 "golang.org/x/tools/go/loader"
2224)
2325
26+ var loadDebugf = logutils .Debug ("load" )
27+
2428func isFullImportNeeded (linters []linter.Config ) bool {
2529 for _ , linter := range linters {
2630 if linter .NeedsProgramLoading () {
@@ -64,6 +68,89 @@ func normalizePaths(paths []string) ([]string, error) {
6468 return ret , nil
6569}
6670
71+ func getCurrentProjectImportPath () (string , error ) {
72+ gopath := os .Getenv ("GOPATH" )
73+ if gopath == "" {
74+ return "" , fmt .Errorf ("no GOPATH env variable" )
75+ }
76+
77+ wd , err := os .Getwd ()
78+ if err != nil {
79+ return "" , fmt .Errorf ("can't get workind directory: %s" , err )
80+ }
81+
82+ if ! strings .HasPrefix (wd , gopath ) {
83+ return "" , fmt .Errorf ("currently no in gopath: %q isn't a prefix of %q" , gopath , wd )
84+ }
85+
86+ path := strings .TrimPrefix (wd , gopath )
87+ path = strings .TrimPrefix (path , string (os .PathSeparator )) // if GOPATH contains separator at the end
88+ src := "src" + string (os .PathSeparator )
89+ if ! strings .HasPrefix (path , src ) {
90+ return "" , fmt .Errorf ("currently no in gopath/src: %q isn't a prefix of %q" , src , path )
91+ }
92+
93+ path = strings .TrimPrefix (path , src )
94+ path = strings .Replace (path , string (os .PathSeparator ), "/" , - 1 )
95+ return path , nil
96+ }
97+
98+ func isLocalProjectAnalysis (args []string ) bool {
99+ for _ , arg := range args {
100+ if strings .HasPrefix (arg , ".." ) || filepath .IsAbs (arg ) {
101+ return false
102+ }
103+ }
104+
105+ return true
106+ }
107+
108+ func getTypeCheckFuncBodies (cfg * config.Run , linters []linter.Config , pkgProg * packages.Program ) func (string ) bool {
109+ if ! isLocalProjectAnalysis (cfg .Args ) {
110+ loadDebugf ("analysis in nonlocal, don't optimize loading by not typechecking func bodies" )
111+ return nil
112+ }
113+
114+ if isSSAReprNeeded (linters ) {
115+ loadDebugf ("ssa repr is needed, don't optimize loading by not typechecking func bodies" )
116+ return nil
117+ }
118+
119+ if len (pkgProg .Dirs ()) == 0 {
120+ // files run, in this mode packages are fake: can't check their path properly
121+ return nil
122+ }
123+
124+ projPath , err := getCurrentProjectImportPath ()
125+ if err != nil {
126+ logrus .Infof ("can't get cur project path: %s" , err )
127+ return nil
128+ }
129+
130+ return func (path string ) bool {
131+ if strings .HasPrefix (path , "." ) {
132+ loadDebugf ("%s: dot import: typecheck func bodies" , path )
133+ return true
134+ }
135+
136+ isLocalPath := strings .HasPrefix (path , projPath )
137+ if isLocalPath {
138+ localPath := strings .TrimPrefix (path , projPath )
139+ localPath = strings .TrimPrefix (localPath , "/" )
140+ if strings .HasPrefix (localPath , "vendor/" ) {
141+ loadDebugf ("%s: local vendor import: DO NOT typecheck func bodies" , path )
142+ return false
143+ }
144+
145+ loadDebugf ("%s: local import: typecheck func bodies" , path )
146+ return true
147+ }
148+
149+ loadDebugf ("%s: not local import: DO NOT typecheck func bodies" , path )
150+ return false
151+ }
152+ }
153+
67154func loadWholeAppIfNeeded (ctx context.Context , linters []linter.Config , cfg * config.Run , pkgProg * packages.Program ) (* loader.Program , * loader.Config , error ) {
68155 if ! isFullImportNeeded (linters ) {
69156 return nil , nil , nil
@@ -76,9 +163,10 @@ func loadWholeAppIfNeeded(ctx context.Context, linters []linter.Config, cfg *con
76163
77164 bctx := pkgProg .BuildContext ()
78165 loadcfg := & loader.Config {
79- Build : bctx ,
80- AllowErrors : true , // Try to analyze partially
81- ParserMode : parser .ParseComments , // AST will be reused by linters
166+ Build : bctx ,
167+ AllowErrors : true , // Try to analyze partially
168+ ParserMode : parser .ParseComments , // AST will be reused by linters
169+ TypeCheckFuncBodies : getTypeCheckFuncBodies (cfg , linters , pkgProg ),
82170 }
83171
84172 var loaderArgs []string
0 commit comments