Skip to content

Commit 7b360fd

Browse files
committed
tt
1 parent deb9613 commit 7b360fd

File tree

6 files changed

+419
-11
lines changed

6 files changed

+419
-11
lines changed

internal/plugins/react_hooks/code_path_analysis/break_context.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,116 @@ func (s *CodePathState) getBreakContext(label string) *BreakContext {
7676

7777
return nil
7878
}
79+
80+
// Makes a path for a `continue` statement.
81+
//
82+
// It makes a looping path.
83+
// It makes new unreachable segment, then it set the head with the segment.
84+
func (s *CodePathState) MakeContinue(label string) {
85+
forkContext := s.forkContext
86+
87+
if !forkContext.IsReachable() {
88+
return
89+
}
90+
91+
context := s.getContinueContext(label)
92+
93+
if context != nil {
94+
if context.continueDestSegments != nil {
95+
s.MakeLooped(forkContext.Head(), context.continueDestSegments)
96+
97+
// If the context is a for-in/of loop, this effects a break also.
98+
if context.kind == ForInStatement || context.kind == ForOfStatement {
99+
context.brokenForkContext.Add(forkContext.Head())
100+
}
101+
} else {
102+
context.continueForkContext.Add(forkContext.Head())
103+
}
104+
}
105+
forkContext.ReplaceHead(forkContext.MakeUnreachable(-1, -1))
106+
}
107+
108+
// Gets a loop-context for a `continue` statement.
109+
func (s *CodePathState) getContinueContext(label string) *LoopContext {
110+
if label == "" {
111+
return s.loopContext
112+
}
113+
114+
context := s.loopContext
115+
for context != nil {
116+
if context.label == label {
117+
return context
118+
}
119+
context = context.upper
120+
}
121+
122+
return nil
123+
}
124+
125+
// Makes a path for a `return` statement.
126+
//
127+
// It registers the head segment to a context of `return`.
128+
// It makes new unreachable segment, then it set the head with the segment.
129+
func (s *CodePathState) MakeReturn() {
130+
forkContext := s.forkContext
131+
132+
if forkContext.IsReachable() {
133+
returnCtx := s.getReturnContext()
134+
if returnCtx != nil {
135+
returnCtx.returnedForkContext.Add(forkContext.Head())
136+
}
137+
forkContext.ReplaceHead(forkContext.MakeUnreachable(-1, -1))
138+
}
139+
}
140+
141+
// Gets a context for a `return` statement.
142+
func (s *CodePathState) getReturnContext() *TryContext {
143+
context := s.tryContext
144+
145+
for context != nil {
146+
if context.hasFinalizer && context.position != "finally" {
147+
return context
148+
}
149+
context = context.upper
150+
}
151+
152+
return nil
153+
}
154+
155+
// Makes a path for a `throw` statement.
156+
//
157+
// It registers the head segment to a context of `throw`.
158+
// It makes new unreachable segment, then it set the head with the segment.
159+
func (s *CodePathState) MakeThrow() {
160+
forkContext := s.forkContext
161+
162+
if forkContext.IsReachable() {
163+
throwCtx := s.getThrowContext()
164+
if throwCtx != nil {
165+
throwCtx.thrownForkContext.Add(forkContext.Head())
166+
}
167+
forkContext.ReplaceHead(forkContext.MakeUnreachable(-1, -1))
168+
}
169+
}
170+
171+
func (s *CodePathState) getThrowContext() *TryContext {
172+
context := s.tryContext
173+
174+
for context != nil {
175+
if context.position == "try" || (context.hasFinalizer && context.position == "catch") {
176+
return context
177+
}
178+
context = context.upper
179+
}
180+
181+
return nil
182+
}
183+
184+
// Makes the final path.
185+
func (s *CodePathState) MakeFinal() {
186+
segments := s.HeadSegments()
187+
188+
if len(segments) > 0 && segments[0].reachable {
189+
s.returnedForkContext.Add((segments))
190+
}
191+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package code_path_analyzer
2+
3+
type CodePath struct {
4+
id string // An identifier
5+
origin string // The type of code path origin
6+
upper *CodePath // The code path of the upper function scope
7+
onLooped func() // A callback funciton to notify looping
8+
childCodePaths []*CodePath // The code paths of nested function scopes
9+
state *CodePathState // The state of the code path
10+
}

internal/plugins/react_hooks/code_path_analysis/code_path_analyzer.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ import (
66

77
type CodePathAnalyzer struct {
88
currentNode *ast.Node
9+
codePath *CodePath
10+
idGenerator *IdGenerator
11+
}
12+
13+
func NewCodePathAnalyzer() *CodePathAnalyzer {
14+
return &CodePathAnalyzer{
15+
currentNode: nil,
16+
codePath: nil,
17+
idGenerator: NewIdGenerator("s"),
18+
}
919
}
1020

1121
// Does the process to enter a given AST node.
@@ -20,7 +30,7 @@ func (analyzer *CodePathAnalyzer) enterNode(node *ast.Node) {
2030

2131
// Updates the code path.
2232
// And emits onCodePathStart/onCodePathSegmentStart events.
23-
// analyzer.processCodePathToEnter(node)
33+
analyzer.processCodePathToEnter(node)
2434

2535
analyzer.currentNode = nil
2636
}
@@ -30,12 +40,40 @@ func (analyzer *CodePathAnalyzer) enterNode(node *ast.Node) {
3040
func (analyzer *CodePathAnalyzer) leaveNode(node *ast.Node) {
3141
analyzer.currentNode = node
3242

33-
// analyzer.processCodePathTOExit(node)
43+
analyzer.processCodePathTOExit(node)
3444

35-
// analyzer.postprocess(node)
45+
analyzer.postprocess(node)
3646

3747
analyzer.currentNode = nil
3848
}
3949

50+
// Updates the code path due to the position of a given node in the parent node thereof.
51+
//
52+
// For example, if the node is `parent.consequent`, this creates a fork from the current path.
4053
func (analyzer *CodePathAnalyzer) preprocess(node *ast.Node) {
54+
codePath := analyzer.codePath
55+
state := codePath.state
56+
parent := node.Parent
57+
58+
switch parent.Kind {
59+
// The `arguments.length == 0` case is in `postprocess` function.
60+
case ast.KindCallExpression:
61+
{
62+
if ast.IsOptionalChain(parent) && len(parent.Arguments()) >= 1 && parent.Arguments()[0] == node {
63+
state.MakeOptionalRight()
64+
}
65+
}
66+
}
67+
}
68+
69+
func (analyzer *CodePathAnalyzer) processCodePathToEnter(node *ast.Node) {
70+
// !!!
71+
}
72+
73+
func (analyzer *CodePathAnalyzer) postprocess(node *ast.Node) {
74+
// !!!
75+
}
76+
77+
func (analyzer *CodePathAnalyzer) processCodePathTOExit(node *ast.Node) {
78+
// !!!
4179
}

internal/plugins/react_hooks/code_path_analysis/code_path_state.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ type CodePathState struct {
1010
switchContext *SwitchContext
1111
tryContext *TryContext
1212
loopContext *LoopContext
13+
14+
currentSegments []*CodePathSegment
15+
initialSegment *CodePathSegment
16+
finalSegments []*CodePathSegment
17+
returnedForkContext *ForkContext
18+
thrownForkContext *ForkContext
1319
}
1420

1521
func NewCodePathState(idGenerator *IdGenerator, onLooped func(fromSegment *CodePathSegment, toSegment *CodePathSegment)) CodePathState {

0 commit comments

Comments
 (0)