Skip to content

Commit 226c384

Browse files
committed
todo
1 parent 4a7c998 commit 226c384

File tree

10 files changed

+277
-1
lines changed

10 files changed

+277
-1
lines changed

error_templates/java/java.go

+2
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ func LoadErrorTemplates(errorTemplates *lib.ErrorTemplates) {
2424
errorTemplates.MustAdd(java.Language, UnclosedCharacterLiteralError)
2525
errorTemplates.MustAdd(java.Language, OperatorCannotBeAppliedError)
2626
errorTemplates.MustAdd(java.Language, PrecisionLossError)
27+
errorTemplates.MustAdd(java.Language, MissingReturnError)
2728
errorTemplates.MustAdd(java.Language, NotAStatementError)
2829
errorTemplates.MustAdd(java.Language, IncompatibleTypesError)
2930
errorTemplates.MustAdd(java.Language, UninitializedVariableError)
3031
errorTemplates.MustAdd(java.Language, AlreadyDefinedError)
32+
errorTemplates.MustAdd(java.Language, PrivateAccessError)
3133
}
3234

3335
func runtimeErrorPattern(errorName string, pattern string) string {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package java
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
lib "github.com/nedpals/errgoengine"
8+
)
9+
10+
type missingReturnErrorCtx struct {
11+
NearestMethod lib.SyntaxNode
12+
}
13+
14+
var MissingReturnError = lib.ErrorTemplate{
15+
Name: "MissingReturnError",
16+
Pattern: comptimeErrorPattern(`missing return statement`),
17+
StackTracePattern: comptimeStackTracePattern,
18+
OnAnalyzeErrorFn: func(cd *lib.ContextData, m *lib.MainError) {
19+
// get nearest method declaration
20+
mCtx := missingReturnErrorCtx{}
21+
rootNode := lib.WrapNode(m.Document, m.Document.Tree.RootNode())
22+
pos := m.ErrorNode.StartPos
23+
lib.QueryNode(rootNode, strings.NewReader("(method_declaration) @method"), func(ctx lib.QueryNodeCtx) bool {
24+
match := ctx.Cursor.FilterPredicates(ctx.Match, []byte(m.Nearest.Doc.Contents))
25+
for _, c := range match.Captures {
26+
pointA := c.Node.StartPoint()
27+
pointB := c.Node.EndPoint()
28+
if uint32(pos.Line) >= pointA.Row+1 && uint32(pos.Line) <= pointB.Row+1 {
29+
node := lib.WrapNode(m.Nearest.Doc, c.Node)
30+
mCtx.NearestMethod = node
31+
return false
32+
}
33+
}
34+
return true
35+
})
36+
fmt.Println(mCtx.NearestMethod.Text())
37+
m.Context = mCtx
38+
},
39+
OnGenExplainFn: func(cd *lib.ContextData, gen *lib.ExplainGenerator) {
40+
gen.Add("This error occurs when a method is declared to return a value, but there is no return statement within the method.")
41+
},
42+
OnGenBugFixFn: func(cd *lib.ContextData, gen *lib.BugFixGenerator) {
43+
ctx := cd.MainError.Context.(missingReturnErrorCtx)
44+
45+
// TODO
46+
gen.Add("Provide a return statement", func(s *lib.BugFixSuggestion) {
47+
bodyNode := ctx.NearestMethod.ChildByFieldName("body")
48+
lastStartPosInBlock := bodyNode.EndPosition()
49+
lastEndPosInBlock := bodyNode.EndPosition()
50+
if bodyNode.NamedChildCount() > 0 {
51+
lastStartPosInBlock = bodyNode.LastNamedChild().StartPosition()
52+
lastEndPosInBlock = bodyNode.LastNamedChild().EndPosition()
53+
}
54+
55+
s.AddStep(
56+
"Since the `%s` method is declared to return an `%s`, you need to provide a return statement with the result",
57+
ctx.NearestMethod.ChildByFieldName("name").Text(),
58+
ctx.NearestMethod.ChildByFieldName("type").Text(),
59+
).AddFix(lib.FixSuggestion{
60+
NewText: "\n" + cd.MainError.Document.LineAt(lastStartPosInBlock.Line)[:lastStartPosInBlock.Column] + fmt.Sprintf("return %s;", ctx.NearestMethod.ChildByFieldName("type").Text()),
61+
StartPosition: lastEndPosInBlock,
62+
EndPosition: lastEndPosInBlock,
63+
Description: "This ensures that the method returns the sum of the two input numbers.",
64+
})
65+
})
66+
67+
gen.Add("Set the method return type to void", func(s *lib.BugFixSuggestion) {
68+
s.AddStep(
69+
"If you don't intend to return a value from the `%s` method, you can change its return type to `void`.",
70+
ctx.NearestMethod.ChildByFieldName("name").Text(),
71+
).AddFix(lib.FixSuggestion{
72+
NewText: "void",
73+
StartPosition: ctx.NearestMethod.ChildByFieldName("type").StartPosition(),
74+
EndPosition: ctx.NearestMethod.ChildByFieldName("type").EndPosition(),
75+
Description: "This is appropriate if you're using the method for side effects rather than returning a value.",
76+
})
77+
})
78+
},
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package java
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
lib "github.com/nedpals/errgoengine"
8+
)
9+
10+
type privateAccessErrorCtx struct {
11+
ClassDeclarationNode lib.SyntaxNode
12+
}
13+
14+
var PrivateAccessError = lib.ErrorTemplate{
15+
Name: "PrivateAccessError",
16+
Pattern: comptimeErrorPattern(`(?P<field>\S+) has private access in (?P<class>\S+)`),
17+
StackTracePattern: comptimeStackTracePattern,
18+
OnAnalyzeErrorFn: func(cd *lib.ContextData, m *lib.MainError) {
19+
pCtx := privateAccessErrorCtx{}
20+
className := cd.Variables["class"]
21+
rootNode := lib.WrapNode(m.Nearest.Doc, m.Nearest.Doc.Tree.RootNode())
22+
23+
// locate the right node first
24+
query := fmt.Sprintf(`((field_access (identifier) . (identifier) @field-name) @field (#eq? @field-name "%s"))`, cd.Variables["field"])
25+
lib.QueryNode(rootNode, strings.NewReader(query), func(ctx lib.QueryNodeCtx) bool {
26+
match := ctx.Cursor.FilterPredicates(ctx.Match, []byte(m.Nearest.Doc.Contents))
27+
for _, c := range match.Captures {
28+
node := lib.WrapNode(m.Nearest.Doc, c.Node)
29+
m.Nearest = node
30+
return false
31+
}
32+
return true
33+
})
34+
35+
// get class declaration node
36+
classQuery := fmt.Sprintf(`(class_declaration name: (identifier) @class-name (#eq? @class-name "%s"))`, className)
37+
lib.QueryNode(rootNode, strings.NewReader(classQuery), func(ctx lib.QueryNodeCtx) bool {
38+
match := ctx.Cursor.FilterPredicates(ctx.Match, []byte(m.Nearest.Doc.Contents))
39+
for _, c := range match.Captures {
40+
node := lib.WrapNode(m.Nearest.Doc, c.Node)
41+
pCtx.ClassDeclarationNode = node
42+
return false
43+
}
44+
return true
45+
})
46+
47+
m.Context = pCtx
48+
},
49+
OnGenExplainFn: func(cd *lib.ContextData, gen *lib.ExplainGenerator) {
50+
gen.Add("This error occurs when you try to access a private variable from another class, which is not allowed.")
51+
},
52+
OnGenBugFixFn: func(cd *lib.ContextData, gen *lib.BugFixGenerator) {
53+
// ctx := cd.MainError.Context.(privateAccessErrorCtx)
54+
fmt.Println(cd.MainError.Nearest.String())
55+
fmt.Println(cd.Analyzer.AnalyzeNode(cd.MainError.Nearest))
56+
57+
gen.Add("Use a public accessor method", func(s *lib.BugFixSuggestion) {
58+
// methodCreatorSb := &strings.Builder{}
59+
60+
// get return type of the private field
61+
62+
// methodCreatorSb.WriteString("public ")
63+
64+
// s.AddStep("To access a private variable from another class, create a public accessor method in `%s`", cd.Variables["class"]).
65+
// AddFix()
66+
})
67+
},
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public class MissingReturn {
2+
public int addNumbers(int a, int b) {
3+
// Missing return statement
4+
}
5+
6+
public static void main(String[] args) {
7+
MissingReturn calculator = new MissingReturn();
8+
int result = calculator.addNumbers(5, 7);
9+
System.out.println("Result: " + result);
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
template: "Java.MissingReturnError"
2+
---
3+
MissingReturn.java:4: error: missing return statement
4+
}
5+
^
6+
1 error
7+
===
8+
template: "Java.MissingReturnError"
9+
---
10+
# MissingReturnError
11+
This error occurs when a method is declared to return a value, but there is no return statement within the method.
12+
```
13+
// Missing return statement
14+
}
15+
^
16+
17+
public static void main(String[] args) {
18+
```
19+
## Steps to fix
20+
### 1. Provide a return statement
21+
Since the `addNumbers` method is declared to return an `int`, you need to provide a return statement with the result.
22+
```diff
23+
public class MissingReturn {
24+
public int addNumbers(int a, int b) {
25+
- // Missing return statement
26+
+ // Missing return statement
27+
+ return a;
28+
}
29+
```
30+
This ensures that the method returns the sum of the two input numbers.
31+
32+
### 2. Set the method return type to void
33+
If you don't intend to return a value from the `addNumbers` method, you can change its return type to `void`.
34+
```diff
35+
public class MissingReturn {
36+
- public int addNumbers(int a, int b) {
37+
+ public void addNumbers(int a, int b) {
38+
// Missing return statement
39+
}
40+
```
41+
This is appropriate if you're using the method for side effects rather than returning a value.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
public class Main {
2+
public static void main(String[] args) {
3+
AnotherClass anotherClass = new AnotherClass();
4+
// Attempting to access a private variable from another class
5+
int value = anotherClass.privateVariable;
6+
System.out.println(value);
7+
}
8+
}
9+
10+
class AnotherClass {
11+
private int privateVariable = 10;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
template: "Java.PrivateAccessError"
2+
---
3+
Main.java:5: error: privateVariable has private access in AnotherClass
4+
int value = anotherClass.privateVariable;
5+
^
6+
1 error
7+
===
8+
template: "Java.PrivateAccessError"
9+
---
10+
# AlreadyDefinedError
11+
This error occurs when you try to access a private variable from another class, which is not allowed.
12+
13+
## Steps to fix
14+
### 1. Use a public accessor method
15+
1. To access a private variable from another class, create a public accessor method in `AnotherClass`.
16+
```diff
17+
+ public int getPrivateVariable() {
18+
+ return privateVariable;
19+
+ }
20+
```
21+
2. Then, use this method to get the value in the `Main` class.
22+
```diff
23+
- int value = anotherClass.privateVariable;
24+
+ int value = anotherClass.getPrivateVariable();
25+
```
26+
This way, you respect encapsulation by using a method to access the private variable.
27+
28+
### 2. Make the variable public (not recommended)
29+
1. If you must access the variable directly, you can make it public, but this is generally not recommended for maintaining encapsulation.
30+
```diff
31+
- private int privateVariable = 10;
32+
+ public int privateVariable = 10;
33+
```
34+
2. Access it directly in the `Main` class.
35+
```diff
36+
- int value = anotherClass.privateVariable;
37+
+ int value = anotherClass.privateVariable;
38+
```
39+
Choose the fix that aligns with your design principles. Using an accessor method is a better practice for encapsulation.

languages/java/language.go

+6
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ func (an *javaAnalyzer) AnalyzeNode(n lib.SyntaxNode) lib.Symbol {
7474

7575
sym := an.FindSymbol(n.Text(), int(n.StartByte()))
7676
if sym == nil {
77+
if n.Type() == "type_identifier" {
78+
an.ContextData.
79+
80+
// mark type as unresolved
81+
return lib.UnresolvedSymbol
82+
}
7783
return BuiltinTypes.NullSymbol
7884
}
7985

symbols.go

+17
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ func NewSymbolKindFromString(str string) SymbolKind {
4848

4949
const (
5050
SymbolKindUnknown SymbolKind = 0
51+
SymbolKindUnresolved SymbolKind = iota
5152
SymbolKindBuiltin SymbolKind = iota
5253
SymbolKindClass SymbolKind = iota
5354
SymbolKindFunction SymbolKind = iota
@@ -219,6 +220,22 @@ func (sym ImportSymbol) Location() Location {
219220
}
220221
}
221222

223+
type unresolvedSymbol struct{}
224+
225+
func (sym unresolvedSymbol) Name() string {
226+
return "unresolved"
227+
}
228+
229+
func (sym unresolvedSymbol) Kind() SymbolKind {
230+
return SymbolKindUnresolved
231+
}
232+
233+
func (sym unresolvedSymbol) Location() Location {
234+
return Location{}
235+
}
236+
237+
var UnresolvedSymbol Symbol = unresolvedSymbol{}
238+
222239
// TODO:
223240
// func (sym ImportSymbol) Children() *SymbolTree {
224241
// // TODO:

tests/java/.vscode/settings.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"bugbuddy.path": "/Users/nedpals/Documents/coding/bugbuddy-proto/server/cmd/bugbuddy"
2+
"bugbuddy.path": "/Users/nedpals/Documents/coding/bugbuddy-proto/server/cmd/bugbuddy",
3+
"java.debug.settings.onBuildFailureProceed": true
34
}

0 commit comments

Comments
 (0)