gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/jgautheron/goconst/parser.go (about)

     1  // Package goconst finds repeated strings that could be replaced by a constant.
     2  //
     3  // There are obvious benefits to using constants instead of repeating strings,
     4  // mostly to ease maintenance. Cannot argue against changing a single constant versus many strings.
     5  // While this could be considered a beginner mistake, across time,
     6  // multiple packages and large codebases, some repetition could have slipped in.
     7  package goconst
     8  
     9  import (
    10  	"go/ast"
    11  	"go/parser"
    12  	"go/token"
    13  	"log"
    14  	"os"
    15  	"path/filepath"
    16  	"regexp"
    17  	"strings"
    18  )
    19  
    20  const (
    21  	testSuffix = "_test.go"
    22  )
    23  
    24  type Parser struct {
    25  	// Meant to be passed via New()
    26  	path, ignore               string
    27  	ignoreTests, matchConstant bool
    28  	minLength                  int
    29  
    30  	supportedTokens []token.Token
    31  
    32  	// Internals
    33  	strs   Strings
    34  	consts Constants
    35  }
    36  
    37  // New creates a new instance of the parser.
    38  // This is your entry point if you'd like to use goconst as an API.
    39  func New(path, ignore string, ignoreTests, matchConstant, numbers bool, minLength int) *Parser {
    40  	supportedTokens := []token.Token{token.STRING}
    41  	if numbers {
    42  		supportedTokens = append(supportedTokens, token.INT, token.FLOAT)
    43  	}
    44  
    45  	return &Parser{
    46  		path:            path,
    47  		ignore:          ignore,
    48  		ignoreTests:     ignoreTests,
    49  		matchConstant:   matchConstant,
    50  		minLength:       minLength,
    51  		supportedTokens: supportedTokens,
    52  
    53  		// Initialize the maps
    54  		strs:   Strings{},
    55  		consts: Constants{},
    56  	}
    57  }
    58  
    59  // ParseTree will search the given path for occurrences that could be moved into constants.
    60  // If "..." is appended, the search will be recursive.
    61  func (p *Parser) ParseTree() (Strings, Constants, error) {
    62  	pathLen := len(p.path)
    63  	// Parse recursively the given path if the recursive notation is found
    64  	if pathLen >= 5 && p.path[pathLen-3:] == "..." {
    65  		filepath.Walk(p.path[:pathLen-3], func(path string, f os.FileInfo, err error) error {
    66  			if err != nil {
    67  				log.Println(err)
    68  				// resume walking
    69  				return nil
    70  			}
    71  
    72  			if f.IsDir() {
    73  				p.parseDir(path)
    74  			}
    75  			return nil
    76  		})
    77  	} else {
    78  		p.parseDir(p.path)
    79  	}
    80  	return p.strs, p.consts, nil
    81  }
    82  
    83  func (p *Parser) parseDir(dir string) error {
    84  	fset := token.NewFileSet()
    85  	pkgs, err := parser.ParseDir(fset, dir, func(info os.FileInfo) bool {
    86  		valid, name := true, info.Name()
    87  
    88  		if p.ignoreTests {
    89  			if strings.HasSuffix(name, testSuffix) {
    90  				valid = false
    91  			}
    92  		}
    93  
    94  		if len(p.ignore) != 0 {
    95  			match, err := regexp.MatchString(p.ignore, dir+name)
    96  			if err != nil {
    97  				log.Fatal(err)
    98  				return true
    99  			}
   100  			if match {
   101  				valid = false
   102  			}
   103  		}
   104  
   105  		return valid
   106  	}, 0)
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	for _, pkg := range pkgs {
   112  		for fn, f := range pkg.Files {
   113  			ast.Walk(&treeVisitor{
   114  				fileSet:     fset,
   115  				packageName: pkg.Name,
   116  				fileName:    fn,
   117  				p:           p,
   118  			}, f)
   119  		}
   120  	}
   121  
   122  	return nil
   123  }
   124  
   125  type Strings map[string][]ExtendedPos
   126  type Constants map[string]ConstType
   127  
   128  type ConstType struct {
   129  	token.Position
   130  	Name, packageName string
   131  }
   132  
   133  type ExtendedPos struct {
   134  	token.Position
   135  	packageName string
   136  }