gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/opennota/check/cmd/aligncheck/aligncheck.go (about)

     1  // This program is free software: you can redistribute it and/or modify
     2  // it under the terms of the GNU General Public License as published by
     3  // the Free Software Foundation, either version 3 of the License, or
     4  // (at your option) any later version.
     5  //
     6  // This program is distributed in the hope that it will be useful,
     7  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     8  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     9  // GNU General Public License for more details.
    10  //
    11  // You should have received a copy of the GNU General Public License
    12  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    13  
    14  package main
    15  
    16  import (
    17  	"flag"
    18  	"fmt"
    19  	"go/build"
    20  	"log"
    21  	"os"
    22  	"sort"
    23  	"unsafe"
    24  
    25  	"github.com/kisielk/gotool"
    26  	"golang.org/x/tools/go/loader"
    27  	"go/types"
    28  )
    29  
    30  var stdSizes = types.StdSizes{
    31  	WordSize: int64(unsafe.Sizeof(int(0))),
    32  	MaxAlign: 8,
    33  }
    34  
    35  func main() {
    36  	flag.Parse()
    37  	exitStatus := 0
    38  
    39  	importPaths := gotool.ImportPaths(flag.Args())
    40  	if len(importPaths) == 0 {
    41  		importPaths = []string{"."}
    42  	}
    43  
    44  	ctx := build.Default
    45  	loadcfg := loader.Config{
    46  		Build: &ctx,
    47  	}
    48  	rest, err := loadcfg.FromArgs(importPaths, false)
    49  	if err != nil {
    50  		log.Fatalf("could not parse arguments: %s", err)
    51  	}
    52  	if len(rest) > 0 {
    53  		log.Fatalf("unhandled extra arguments: %v", rest)
    54  	}
    55  
    56  	program, err := loadcfg.Load()
    57  	if err != nil {
    58  		log.Fatalf("could not type check: %s", err)
    59  	}
    60  
    61  	var lines []string
    62  
    63  	for _, pkgInfo := range program.InitialPackages() {
    64  		for _, obj := range pkgInfo.Defs {
    65  			if obj == nil {
    66  				continue
    67  			}
    68  
    69  			if _, ok := obj.(*types.TypeName); !ok {
    70  				continue
    71  			}
    72  
    73  			typ, ok := obj.Type().(*types.Named)
    74  			if !ok {
    75  				continue
    76  			}
    77  
    78  			strukt, ok := typ.Underlying().(*types.Struct)
    79  			if !ok {
    80  				continue
    81  			}
    82  
    83  			structAlign := int(stdSizes.Alignof(strukt))
    84  			structSize := int(stdSizes.Sizeof(strukt))
    85  			if structSize%structAlign != 0 {
    86  				structSize += structAlign - structSize%structAlign
    87  			}
    88  
    89  			minSize := 0
    90  			for i := 0; i < strukt.NumFields(); i++ {
    91  				field := strukt.Field(i)
    92  				fieldType := field.Type()
    93  				typeSize := int(stdSizes.Sizeof(fieldType))
    94  				minSize += typeSize
    95  			}
    96  			if minSize%structAlign != 0 {
    97  				minSize += structAlign - minSize%structAlign
    98  			}
    99  
   100  			if minSize != structSize {
   101  				pos := program.Fset.Position(obj.Pos())
   102  				lines = append(lines, fmt.Sprintf(
   103  					"%s: %s:%d:%d: struct %s could have size %d (currently %d)",
   104  					obj.Pkg().Path(),
   105  					pos.Filename,
   106  					pos.Line,
   107  					pos.Column,
   108  					obj.Name(),
   109  					minSize,
   110  					structSize,
   111  				))
   112  				exitStatus = 1
   113  			}
   114  		}
   115  	}
   116  
   117  	sort.Strings(lines)
   118  	for _, line := range lines {
   119  		fmt.Println(line)
   120  	}
   121  
   122  	os.Exit(exitStatus)
   123  }