Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
yuxincs committed May 30, 2024
1 parent e3d4579 commit 6ebe441
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 64 deletions.
30 changes: 5 additions & 25 deletions assertion/function/preprocess/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import (
"fmt"
"go/ast"
"go/token"
"go/types"
"regexp"

"go.uber.org/nilaway/assertion/function/trustedfunc"
"go.uber.org/nilaway/util"
Expand Down Expand Up @@ -126,13 +124,12 @@ func copyGraph(graph *cfg.CFG) *cfg.CFG {
return newGraph
}

var _noReturnRegex = regexp.MustCompile(
`^(log\.Fatal(f)?|(os\.Exit)|(runtime\.Goexit)|(testing\.(T|B|F|TB)\.(FailNow|Skip|Skipf|SkipNow)))`,
)

// fixNoReturnBlock trims the `Succs` fields of a block if it contains a call to a trusted function
// that does not return (e.g., `os.Exit`, `log.Fatal`). This ensures that our further analysis
// correctly understands that the code is unreachable after such a call.
func (p *Preprocessor) fixNoReturnBlock(block *cfg.Block) {
// No need to fix empty blocks or blocks that already have no successor.
if len(block.Nodes) == 0 { // || len(block.Succs) == 0 {
if len(block.Nodes) == 0 || len(block.Succs) == 0 {
return
}

Expand All @@ -145,24 +142,7 @@ func (p *Preprocessor) fixNoReturnBlock(block *cfg.Block) {
if !ok {
continue
}
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
continue
}

var name string
receiver := util.UnwrapPtr(p.pass.TypesInfo.TypeOf(sel.X))
if receiver == nil {
if pkg, ok := p.pass.TypesInfo.ObjectOf(sel.Sel).(*types.Package); ok {

}
p.pass.TypesInfo.

} else {
name = receiver + "." + sel.Sel.Name
}

if _noReturnRegex.MatchString(name) {
if trustedfunc.TrimSuccsOn(p.pass, call) {
block.Succs = nil
return
}
Expand Down
39 changes: 0 additions & 39 deletions assertion/function/preprocess/cfg_test.go

This file was deleted.

65 changes: 65 additions & 0 deletions assertion/function/trustedfunc/cfg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) 2024 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package trustedfunc

import (
"go/ast"
"regexp"

"golang.org/x/tools/go/analysis"
)

var _cfgTrimSuccs = map[trustedFuncSig]bool{
{
kind: _func,
enclosingRegex: regexp.MustCompile(`^log$`),
funcNameRegex: regexp.MustCompile(`^Fatal(f)?$`),
}: true,
{
kind: _func,
enclosingRegex: regexp.MustCompile(`^os$`),
funcNameRegex: regexp.MustCompile(`^Exit$`),
}: true,
{
kind: _func,
enclosingRegex: regexp.MustCompile(`^runtime$`),
funcNameRegex: regexp.MustCompile(`^Goexit$`),
}: true,
{
kind: _method,
enclosingRegex: regexp.MustCompile(`^testing.(T|B|F|TB)$`),
funcNameRegex: regexp.MustCompile(`^(FailNow|Skip|Skipf|SkipNow)$`),
}: true,
}

// TrimSuccsOn returns true if the call should be treated as a no-return call and hence should have
// the `Succs` field trimmed on its residing CFG block.
//
// Note that this does not really need to be done for most analyzer drivers, as the CFG
// construction (via the [ctrlflow] analyzer) already handles this via the `noReturn` facts (by
// analyzing the sources of stdlib). However, in bazel/nogo, the stdlib is installed via
// `go install`, and hence nogo analyzers do not have access to the stdlib sources, leading to no
// `noReturn` facts being generated for stdlib. Hence, this hook is a workaround to handle
// no-return functions only in stdlib for bazel/nogo. It would be redundant (but harmless) for
// other drivers.
// [ctrlflow]: https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ctrlflow
func TrimSuccsOn(pass *analysis.Pass, call *ast.CallExpr) bool {
for f := range _cfgTrimSuccs {
if f.match(call, pass) {
return true
}
}
return false
}

0 comments on commit 6ebe441

Please sign in to comment.