...

Source file src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go

Documentation: cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package analysisutil defines various helper functions
     6  // used by two or more packages beneath go/analysis.
     7  package analysisutil
     8  
     9  import (
    10  	"bytes"
    11  	"go/ast"
    12  	"go/printer"
    13  	"go/token"
    14  	"go/types"
    15  	"os"
    16  
    17  	"golang.org/x/tools/internal/analysisinternal"
    18  )
    19  
    20  // Format returns a string representation of the expression.
    21  func Format(fset *token.FileSet, x ast.Expr) string {
    22  	var b bytes.Buffer
    23  	printer.Fprint(&b, fset, x)
    24  	return b.String()
    25  }
    26  
    27  // HasSideEffects reports whether evaluation of e has side effects.
    28  func HasSideEffects(info *types.Info, e ast.Expr) bool {
    29  	safe := true
    30  	ast.Inspect(e, func(node ast.Node) bool {
    31  		switch n := node.(type) {
    32  		case *ast.CallExpr:
    33  			typVal := info.Types[n.Fun]
    34  			switch {
    35  			case typVal.IsType():
    36  				// Type conversion, which is safe.
    37  			case typVal.IsBuiltin():
    38  				// Builtin func, conservatively assumed to not
    39  				// be safe for now.
    40  				safe = false
    41  				return false
    42  			default:
    43  				// A non-builtin func or method call.
    44  				// Conservatively assume that all of them have
    45  				// side effects for now.
    46  				safe = false
    47  				return false
    48  			}
    49  		case *ast.UnaryExpr:
    50  			if n.Op == token.ARROW {
    51  				safe = false
    52  				return false
    53  			}
    54  		}
    55  		return true
    56  	})
    57  	return !safe
    58  }
    59  
    60  // ReadFile reads a file and adds it to the FileSet
    61  // so that we can report errors against it using lineStart.
    62  func ReadFile(fset *token.FileSet, filename string) ([]byte, *token.File, error) {
    63  	content, err := os.ReadFile(filename)
    64  	if err != nil {
    65  		return nil, nil, err
    66  	}
    67  	tf := fset.AddFile(filename, -1, len(content))
    68  	tf.SetLinesForContent(content)
    69  	return content, tf, nil
    70  }
    71  
    72  // LineStart returns the position of the start of the specified line
    73  // within file f, or NoPos if there is no line of that number.
    74  func LineStart(f *token.File, line int) token.Pos {
    75  	// Use binary search to find the start offset of this line.
    76  	//
    77  	// TODO(adonovan): eventually replace this function with the
    78  	// simpler and more efficient (*go/token.File).LineStart, added
    79  	// in go1.12.
    80  
    81  	min := 0        // inclusive
    82  	max := f.Size() // exclusive
    83  	for {
    84  		offset := (min + max) / 2
    85  		pos := f.Pos(offset)
    86  		posn := f.Position(pos)
    87  		if posn.Line == line {
    88  			return pos - (token.Pos(posn.Column) - 1)
    89  		}
    90  
    91  		if min+1 >= max {
    92  			return token.NoPos
    93  		}
    94  
    95  		if posn.Line < line {
    96  			min = offset
    97  		} else {
    98  			max = offset
    99  		}
   100  	}
   101  }
   102  
   103  // Imports returns true if path is imported by pkg.
   104  func Imports(pkg *types.Package, path string) bool {
   105  	for _, imp := range pkg.Imports() {
   106  		if imp.Path() == path {
   107  			return true
   108  		}
   109  	}
   110  	return false
   111  }
   112  
   113  // IsNamedType reports whether t is the named type with the given package path
   114  // and one of the given names.
   115  // This function avoids allocating the concatenation of "pkg.Name",
   116  // which is important for the performance of syntax matching.
   117  func IsNamedType(t types.Type, pkgPath string, names ...string) bool {
   118  	n, ok := t.(*types.Named)
   119  	if !ok {
   120  		return false
   121  	}
   122  	obj := n.Obj()
   123  	if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != pkgPath {
   124  		return false
   125  	}
   126  	name := obj.Name()
   127  	for _, n := range names {
   128  		if name == n {
   129  			return true
   130  		}
   131  	}
   132  	return false
   133  }
   134  
   135  // IsFunctionNamed reports whether f is a top-level function defined in the
   136  // given package and has one of the given names.
   137  // It returns false if f is nil or a method.
   138  func IsFunctionNamed(f *types.Func, pkgPath string, names ...string) bool {
   139  	if f == nil {
   140  		return false
   141  	}
   142  	if f.Pkg() == nil || f.Pkg().Path() != pkgPath {
   143  		return false
   144  	}
   145  	if f.Type().(*types.Signature).Recv() != nil {
   146  		return false
   147  	}
   148  	for _, n := range names {
   149  		if f.Name() == n {
   150  			return true
   151  		}
   152  	}
   153  	return false
   154  }
   155  
   156  var MustExtractDoc = analysisinternal.MustExtractDoc
   157  

View as plain text