analyzers

package
v0.0.0-...-d075fa2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2022 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Analyzers = map[string]*analysis.Analyzer{}
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.MemberExpressionMemberInfos[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.AuthAccountAddPublicKeyField:
						replacement = "keys.add"
					case sema.AuthAccountRemovePublicKeyField:
						replacement = "keys.revoke"
					default:
						return
					}

					report(
						analysis.Diagnostic{
							Location: location,
							Range:    ast.NewRangeFromPositioned(nil, memberExpression.Identifier),
							Category: "update recommended",
							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, ok := elaboration.NumberConversionArgumentTypes[expr]
						if !ok {
							return
						}
						diagnostic = suggestIntegerLiteralConversionReplacement(expr, location, argumentData.Type, argumentData.Range)
					case *ast.FixedPointExpression:
						argumentData, ok := elaboration.NumberConversionArgumentTypes[expr]
						if !ok {
							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, ok := elaboration.StaticCastTypes[castingExpression]
					if ok && isRedundantCast(castingExpression.Expression,
						redundantType.ExprActualType,
						redundantType.TargetType,
						redundantType.ExpectedType,
					) {
						report(
							analysis.Diagnostic{
								Location: location,
								Range:    ast.NewRangeFromPositioned(nil, castingExpression.TypeAnnotation),
								Category: "lint",
								Message:  fmt.Sprintf("cast to `%s` is redundant", redundantType.TargetType),
							},
						)
						return
					}

					alwaysSucceedingTypes, ok := elaboration.RuntimeCastTypes[castingExpression]
					if ok && sema.IsSubType(alwaysSucceedingTypes.Left, alwaysSucceedingTypes.Right) {
						switch castingExpression.Operation {
						case ast.OperationFailableCast:
							report(
								analysis.Diagnostic{
									Location: location,
									Range:    ast.NewRangeFromPositioned(nil, castingExpression),
									Category: "lint",
									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: "lint",
									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.MatchString(code[startOffset:endOffset]) {
						return
					}

					report(
						analysis.Diagnostic{
							Location: location,
							Range:    ast.NewRangeFromPositioned(nil, element),
							Category: "update recommended",
							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.ForceExpressionTypes[forceExpression]

					if valueType == nil {
						return
					}

					_, ok = valueType.(*sema.OptionalType)
					if !ok {
						report(
							analysis.Diagnostic{
								Location: location,
								Range:    ast.NewRangeFromPositioned(nil, element),
								Category: "lint",
								Message:  "unnecessary force operator",
							},
						)
					}
				},
			)

			return nil
		},
	}
})()

Functions

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) ast.Repr

func (*CheckCastVisitor) VisitBinaryExpression

func (d *CheckCastVisitor) VisitBinaryExpression(_ *ast.BinaryExpression) ast.Repr

func (*CheckCastVisitor) VisitBoolExpression

func (d *CheckCastVisitor) VisitBoolExpression(_ *ast.BoolExpression) ast.Repr

func (*CheckCastVisitor) VisitCastingExpression

func (d *CheckCastVisitor) VisitCastingExpression(_ *ast.CastingExpression) ast.Repr

func (*CheckCastVisitor) VisitConditionalExpression

func (d *CheckCastVisitor) VisitConditionalExpression(conditionalExpr *ast.ConditionalExpression) ast.Repr

func (*CheckCastVisitor) VisitCreateExpression

func (d *CheckCastVisitor) VisitCreateExpression(_ *ast.CreateExpression) ast.Repr

func (*CheckCastVisitor) VisitDestroyExpression

func (d *CheckCastVisitor) VisitDestroyExpression(_ *ast.DestroyExpression) ast.Repr

func (*CheckCastVisitor) VisitDictionaryExpression

func (d *CheckCastVisitor) VisitDictionaryExpression(expr *ast.DictionaryExpression) ast.Repr

func (*CheckCastVisitor) VisitFixedPointExpression

func (d *CheckCastVisitor) VisitFixedPointExpression(expr *ast.FixedPointExpression) ast.Repr

func (*CheckCastVisitor) VisitForceExpression

func (d *CheckCastVisitor) VisitForceExpression(_ *ast.ForceExpression) ast.Repr

func (*CheckCastVisitor) VisitFunctionExpression

func (d *CheckCastVisitor) VisitFunctionExpression(_ *ast.FunctionExpression) ast.Repr

func (*CheckCastVisitor) VisitIdentifierExpression

func (d *CheckCastVisitor) VisitIdentifierExpression(_ *ast.IdentifierExpression) ast.Repr

func (*CheckCastVisitor) VisitIndexExpression

func (d *CheckCastVisitor) VisitIndexExpression(_ *ast.IndexExpression) ast.Repr

func (*CheckCastVisitor) VisitIntegerExpression

func (d *CheckCastVisitor) VisitIntegerExpression(_ *ast.IntegerExpression) ast.Repr

func (*CheckCastVisitor) VisitInvocationExpression

func (d *CheckCastVisitor) VisitInvocationExpression(_ *ast.InvocationExpression) ast.Repr

func (*CheckCastVisitor) VisitMemberExpression

func (d *CheckCastVisitor) VisitMemberExpression(_ *ast.MemberExpression) ast.Repr

func (*CheckCastVisitor) VisitNilExpression

func (d *CheckCastVisitor) VisitNilExpression(_ *ast.NilExpression) ast.Repr

func (*CheckCastVisitor) VisitPathExpression

func (d *CheckCastVisitor) VisitPathExpression(_ *ast.PathExpression) ast.Repr

func (*CheckCastVisitor) VisitReferenceExpression

func (d *CheckCastVisitor) VisitReferenceExpression(_ *ast.ReferenceExpression) ast.Repr

func (*CheckCastVisitor) VisitStringExpression

func (d *CheckCastVisitor) VisitStringExpression(_ *ast.StringExpression) ast.Repr

func (*CheckCastVisitor) VisitUnaryExpression

func (d *CheckCastVisitor) VisitUnaryExpression(_ *ast.UnaryExpression) ast.Repr

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL