Documentation
¶
Index ¶
- Constants
- Variables
- func RegisterAnalyzer(name string, analyzer *analysis.Analyzer)
- func ReplacementHint(expr ast.Expression, location common.Location, r ast.Range) *analysis.Diagnostic
- type CheckCastVisitor
- func (d *CheckCastVisitor) IsRedundantCast(expr ast.Expression, exprInferredType, targetType sema.Type) bool
- func (d *CheckCastVisitor) VisitArrayExpression(expr *ast.ArrayExpression) bool
- func (d *CheckCastVisitor) VisitAttachExpression(_ *ast.AttachExpression) bool
- func (d *CheckCastVisitor) VisitBinaryExpression(_ *ast.BinaryExpression) bool
- func (d *CheckCastVisitor) VisitBoolExpression(_ *ast.BoolExpression) bool
- func (d *CheckCastVisitor) VisitCastingExpression(_ *ast.CastingExpression) bool
- func (d *CheckCastVisitor) VisitConditionalExpression(conditionalExpr *ast.ConditionalExpression) bool
- func (d *CheckCastVisitor) VisitCreateExpression(_ *ast.CreateExpression) bool
- func (d *CheckCastVisitor) VisitDestroyExpression(_ *ast.DestroyExpression) bool
- func (d *CheckCastVisitor) VisitDictionaryExpression(expr *ast.DictionaryExpression) bool
- func (d *CheckCastVisitor) VisitFixedPointExpression(expr *ast.FixedPointExpression) bool
- func (d *CheckCastVisitor) VisitForceExpression(_ *ast.ForceExpression) bool
- func (d *CheckCastVisitor) VisitFunctionExpression(_ *ast.FunctionExpression) bool
- func (d *CheckCastVisitor) VisitIdentifierExpression(_ *ast.IdentifierExpression) bool
- func (d *CheckCastVisitor) VisitIndexExpression(_ *ast.IndexExpression) bool
- func (d *CheckCastVisitor) VisitIntegerExpression(_ *ast.IntegerExpression) bool
- func (d *CheckCastVisitor) VisitInvocationExpression(_ *ast.InvocationExpression) bool
- func (d *CheckCastVisitor) VisitMemberExpression(_ *ast.MemberExpression) bool
- func (d *CheckCastVisitor) VisitNilExpression(_ *ast.NilExpression) bool
- func (d *CheckCastVisitor) VisitPathExpression(_ *ast.PathExpression) bool
- func (d *CheckCastVisitor) VisitReferenceExpression(_ *ast.ReferenceExpression) bool
- func (d *CheckCastVisitor) VisitStringExpression(_ *ast.StringExpression) bool
- func (d *CheckCastVisitor) VisitUnaryExpression(_ *ast.UnaryExpression) bool
- func (d *CheckCastVisitor) VisitVoidExpression(_ *ast.VoidExpression) bool
- type Config
- type Linter
- func (l *Linter) AnalyzeAccount(address string, networkName string)
- func (l *Linter) AnalyzeCSV(path string)
- func (l *Linter) AnalyzeDirectory(directory string)
- func (l *Linter) AnalyzeTransaction(transactionID flow.Identifier, networkName string)
- func (l *Linter) PrettyPrintError(err error, location common.Location)
Constants ¶
View Source
const ( ReplacementCategory = "replacement-hint" RemovalCategory = "removal-hint" UpdateCategory = "update recommended" UnnecessaryCastCategory = "unnecessary-cast-hint" )
View Source
const LoadMode = analysis.NeedTypes | analysis.NeedExtendedElaboration
Variables ¶
View Source
var Analyzers = map[string]*analysis.Analyzer{}
View Source
var AuthAccountParameterAnalyzer = (func() *analysis.Analyzer { elementFilter := []ast.Element{ (*ast.FunctionDeclaration)(nil), (*ast.SpecialFunctionDeclaration)(nil), } return &analysis.Analyzer{ Description: "Detects functions with AuthAccount type parameters", Requires: []*analysis.Analyzer{ analysis.InspectorAnalyzer, }, Run: func(pass *analysis.Pass) interface{} { inspector := pass.ResultOf[analysis.InspectorAnalyzer].(*ast.Inspector) location := pass.Program.Location report := pass.Report inspector.Preorder( elementFilter, func(element ast.Element) { var parameterList *ast.ParameterList switch declaration := element.(type) { case *ast.FunctionDeclaration: parameterList = declaration.ParameterList case *ast.SpecialFunctionDeclaration: if declaration.DeclarationKind() == common.DeclarationKindInitializer { parameterList = declaration.FunctionDeclaration.ParameterList } } if parameterList == nil { return } for _, parameter := range parameterList.Parameters { nominalType, ok := parameter.TypeAnnotation.Type.(*ast.NominalType) if ok && nominalType.Identifier.Identifier == "AuthAccount" { report( analysis.Diagnostic{ Location: location, Range: ast.NewRangeFromPositioned(nil, element), Category: UpdateCategory, Message: "It is an anti-pattern to pass AuthAccount to functions.", SecondaryMessage: "Consider using Capabilities instead.", }, ) } } }, ) return nil }, } })()
View Source
var DeprecatedKeyFunctionsAnalyzer = (func() *analysis.Analyzer { elementFilter := []ast.Element{ (*ast.InvocationExpression)(nil), } return &analysis.Analyzer{ Description: "Detects usages of the deprecated key management API. It will be removed in a future release.", Requires: []*analysis.Analyzer{ analysis.InspectorAnalyzer, }, Run: func(pass *analysis.Pass) interface{} { inspector := pass.ResultOf[analysis.InspectorAnalyzer].(*ast.Inspector) location := pass.Program.Location elaboration := pass.Program.Elaboration report := pass.Report inspector.Preorder( elementFilter, func(element ast.Element) { invocationExpression, ok := element.(*ast.InvocationExpression) if !ok { return } memberExpression, ok := invocationExpression.InvokedExpression.(*ast.MemberExpression) if !ok { return } memberInfo, _ := elaboration.MemberExpressionMemberInfo(memberExpression) member := memberInfo.Member if member == nil { return } if member.ContainerType != sema.AuthAccountType { return } var replacement string functionName := member.Identifier.Identifier switch functionName { case sema.AuthAccountTypeAddPublicKeyFunctionName: replacement = "keys.add" case sema.AuthAccountTypeRemovePublicKeyFunctionName: replacement = "keys.revoke" default: return } report( analysis.Diagnostic{ Location: location, Range: ast.NewRangeFromPositioned(nil, memberExpression.Identifier), Category: UpdateCategory, Message: fmt.Sprintf( "deprecated function '%s' will get removed", functionName, ), SecondaryMessage: fmt.Sprintf( "replace with '%s'", replacement, ), }, ) }, ) return nil }, } })()
View Source
var NumberFunctionArgumentAnalyzer = (func() *analysis.Analyzer { elementFilter := []ast.Element{ (*ast.IntegerExpression)(nil), (*ast.FixedPointExpression)(nil), } return &analysis.Analyzer{ Description: "Detects redundant uses of number conversion functions.", Requires: []*analysis.Analyzer{ analysis.InspectorAnalyzer, }, Run: func(pass *analysis.Pass) interface{} { inspector := pass.ResultOf[analysis.InspectorAnalyzer].(*ast.Inspector) location := pass.Program.Location elaboration := pass.Program.Elaboration report := pass.Report inspector.Preorder( elementFilter, func(element ast.Element) { var diagnostic *analysis.Diagnostic switch expr := element.(type) { case *ast.IntegerExpression: argumentData := elaboration.NumberConversionArgumentTypes(expr) if argumentData.Type == nil { return } diagnostic = suggestIntegerLiteralConversionReplacement( expr, location, argumentData.Type, argumentData.Range, ) case *ast.FixedPointExpression: argumentData := elaboration.NumberConversionArgumentTypes(expr) if argumentData.Type == nil { return } diagnostic = suggestFixedPointLiteralConversionReplacement( expr, location, argumentData.Type, argumentData.Range, ) default: return } if diagnostic != nil { report(*diagnostic) } }, ) return nil }, } })()
View Source
var RedundantCastAnalyzer = (func() *analysis.Analyzer { elementFilter := []ast.Element{ (*ast.CastingExpression)(nil), } return &analysis.Analyzer{ Description: "Detects unnecessary cast expressions", Requires: []*analysis.Analyzer{ analysis.InspectorAnalyzer, }, Run: func(pass *analysis.Pass) interface{} { inspector := pass.ResultOf[analysis.InspectorAnalyzer].(*ast.Inspector) location := pass.Program.Location elaboration := pass.Program.Elaboration report := pass.Report inspector.Preorder( elementFilter, func(element ast.Element) { castingExpression, ok := element.(*ast.CastingExpression) if !ok { return } redundantType := elaboration.StaticCastTypes(castingExpression) if redundantType.ExprActualType != nil && isRedundantCast( castingExpression.Expression, redundantType.ExprActualType, redundantType.TargetType, redundantType.ExpectedType, ) { report( analysis.Diagnostic{ Location: location, Range: ast.NewRangeFromPositioned(nil, castingExpression.TypeAnnotation), Category: UnnecessaryCastCategory, Message: fmt.Sprintf("cast to `%s` is redundant", redundantType.TargetType), }, ) return } alwaysSucceedingTypes := elaboration.RuntimeCastTypes(castingExpression) if alwaysSucceedingTypes.Left != nil && sema.IsSubType(alwaysSucceedingTypes.Left, alwaysSucceedingTypes.Right) { switch castingExpression.Operation { case ast.OperationFailableCast: report( analysis.Diagnostic{ Location: location, Range: ast.NewRangeFromPositioned(nil, castingExpression), Category: UnnecessaryCastCategory, Message: fmt.Sprintf("failable cast ('%s') from `%s` to `%s` always succeeds", ast.OperationFailableCast.Symbol(), alwaysSucceedingTypes.Left, alwaysSucceedingTypes.Right), }, ) case ast.OperationForceCast: report( analysis.Diagnostic{ Location: location, Range: ast.NewRangeFromPositioned(nil, castingExpression), Category: UnnecessaryCastCategory, Message: fmt.Sprintf("force cast ('%s') from `%s` to `%s` always succeeds", ast.OperationForceCast.Symbol(), alwaysSucceedingTypes.Left, alwaysSucceedingTypes.Right), }, ) default: panic(errors.NewUnreachableError()) } } }, ) return nil }, } })()
View Source
var ReferenceOperatorAnalyzer = (func() *analysis.Analyzer { elementFilter := []ast.Element{ (*ast.ReferenceExpression)(nil), } invalidOperatorRegexp := regexp.MustCompile(`.*\bas[?!].*`) return &analysis.Analyzer{ Description: "Detects invalid operators in reference expressions. These will get rejected in a future release.", Requires: []*analysis.Analyzer{ analysis.InspectorAnalyzer, }, Run: func(pass *analysis.Pass) interface{} { inspector := pass.ResultOf[analysis.InspectorAnalyzer].(*ast.Inspector) location := pass.Program.Location code := pass.Program.Code report := pass.Report inspector.Preorder( elementFilter, func(element ast.Element) { referenceExpression, ok := element.(*ast.ReferenceExpression) if !ok { return } startOffset := referenceExpression.Expression.EndPosition(nil).Offset + 1 endOffset := referenceExpression.Type.StartPosition().Offset - 1 if !invalidOperatorRegexp.Match(code[startOffset:endOffset]) { return } report( analysis.Diagnostic{ Location: location, Range: ast.NewRangeFromPositioned(nil, element), Category: UpdateCategory, Message: "incorrect reference operator used", SecondaryMessage: fmt.Sprintf( "use the '%s' operator", ast.OperationCast.Symbol(), ), }, ) }, ) return nil }, } })()
View Source
var UnnecessaryForceAnalyzer = (func() *analysis.Analyzer { elementFilter := []ast.Element{ (*ast.ForceExpression)(nil), } return &analysis.Analyzer{ Description: "Detects unnecessary uses of the force operator", Requires: []*analysis.Analyzer{ analysis.InspectorAnalyzer, }, Run: func(pass *analysis.Pass) interface{} { inspector := pass.ResultOf[analysis.InspectorAnalyzer].(*ast.Inspector) location := pass.Program.Location elaboration := pass.Program.Elaboration report := pass.Report inspector.Preorder( elementFilter, func(element ast.Element) { forceExpression, ok := element.(*ast.ForceExpression) if !ok { return } valueType := elaboration.ForceExpressionType(forceExpression) if valueType == nil { return } _, ok = valueType.(*sema.OptionalType) if !ok { report( analysis.Diagnostic{ Location: location, Range: ast.NewRangeFromPositioned(nil, element), Category: RemovalCategory, Message: "unnecessary force operator", }, ) } }, ) return nil }, } })()
Functions ¶
func RegisterAnalyzer ¶ added in v0.5.0
func ReplacementHint ¶
func ReplacementHint( expr ast.Expression, location common.Location, r ast.Range, ) *analysis.Diagnostic
Types ¶
type CheckCastVisitor ¶
type CheckCastVisitor struct {
// contains filtered or unexported fields
}
func (*CheckCastVisitor) IsRedundantCast ¶
func (d *CheckCastVisitor) IsRedundantCast(expr ast.Expression, exprInferredType, targetType sema.Type) bool
func (*CheckCastVisitor) VisitArrayExpression ¶
func (d *CheckCastVisitor) VisitArrayExpression(expr *ast.ArrayExpression) bool
func (*CheckCastVisitor) VisitAttachExpression ¶ added in v0.5.0
func (d *CheckCastVisitor) VisitAttachExpression(_ *ast.AttachExpression) bool
func (*CheckCastVisitor) VisitBinaryExpression ¶
func (d *CheckCastVisitor) VisitBinaryExpression(_ *ast.BinaryExpression) bool
func (*CheckCastVisitor) VisitBoolExpression ¶
func (d *CheckCastVisitor) VisitBoolExpression(_ *ast.BoolExpression) bool
func (*CheckCastVisitor) VisitCastingExpression ¶
func (d *CheckCastVisitor) VisitCastingExpression(_ *ast.CastingExpression) bool
func (*CheckCastVisitor) VisitConditionalExpression ¶
func (d *CheckCastVisitor) VisitConditionalExpression(conditionalExpr *ast.ConditionalExpression) bool
func (*CheckCastVisitor) VisitCreateExpression ¶
func (d *CheckCastVisitor) VisitCreateExpression(_ *ast.CreateExpression) bool
func (*CheckCastVisitor) VisitDestroyExpression ¶
func (d *CheckCastVisitor) VisitDestroyExpression(_ *ast.DestroyExpression) bool
func (*CheckCastVisitor) VisitDictionaryExpression ¶
func (d *CheckCastVisitor) VisitDictionaryExpression(expr *ast.DictionaryExpression) bool
func (*CheckCastVisitor) VisitFixedPointExpression ¶
func (d *CheckCastVisitor) VisitFixedPointExpression(expr *ast.FixedPointExpression) bool
func (*CheckCastVisitor) VisitForceExpression ¶
func (d *CheckCastVisitor) VisitForceExpression(_ *ast.ForceExpression) bool
func (*CheckCastVisitor) VisitFunctionExpression ¶
func (d *CheckCastVisitor) VisitFunctionExpression(_ *ast.FunctionExpression) bool
func (*CheckCastVisitor) VisitIdentifierExpression ¶
func (d *CheckCastVisitor) VisitIdentifierExpression(_ *ast.IdentifierExpression) bool
func (*CheckCastVisitor) VisitIndexExpression ¶
func (d *CheckCastVisitor) VisitIndexExpression(_ *ast.IndexExpression) bool
func (*CheckCastVisitor) VisitIntegerExpression ¶
func (d *CheckCastVisitor) VisitIntegerExpression(_ *ast.IntegerExpression) bool
func (*CheckCastVisitor) VisitInvocationExpression ¶
func (d *CheckCastVisitor) VisitInvocationExpression(_ *ast.InvocationExpression) bool
func (*CheckCastVisitor) VisitMemberExpression ¶
func (d *CheckCastVisitor) VisitMemberExpression(_ *ast.MemberExpression) bool
func (*CheckCastVisitor) VisitNilExpression ¶
func (d *CheckCastVisitor) VisitNilExpression(_ *ast.NilExpression) bool
func (*CheckCastVisitor) VisitPathExpression ¶
func (d *CheckCastVisitor) VisitPathExpression(_ *ast.PathExpression) bool
func (*CheckCastVisitor) VisitReferenceExpression ¶
func (d *CheckCastVisitor) VisitReferenceExpression(_ *ast.ReferenceExpression) bool
func (*CheckCastVisitor) VisitStringExpression ¶
func (d *CheckCastVisitor) VisitStringExpression(_ *ast.StringExpression) bool
func (*CheckCastVisitor) VisitUnaryExpression ¶
func (d *CheckCastVisitor) VisitUnaryExpression(_ *ast.UnaryExpression) bool
func (*CheckCastVisitor) VisitVoidExpression ¶
func (d *CheckCastVisitor) VisitVoidExpression(_ *ast.VoidExpression) bool
type Linter ¶
type Linter struct { Config Config Codes map[common.Location][]byte // contains filtered or unexported fields }
func (*Linter) AnalyzeAccount ¶
func (*Linter) AnalyzeCSV ¶
func (*Linter) AnalyzeDirectory ¶
func (*Linter) AnalyzeTransaction ¶
Source Files
¶
Click to show internal directories.
Click to hide internal directories.