Skip to content

Commit 4a09bad

Browse files
authored
Merge pull request #221 from facchinm/FunctionPointerAsArgumentFixed_squashed
Fix prototypes line insertion logic
2 parents f7ec17f + 0a6f354 commit 4a09bad

10 files changed

+173
-37
lines changed

Diff for: src/arduino.cc/builder/ctags/ctags_parser.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,16 @@ var KNOWN_TAG_KINDS = map[string]bool{
5353
}
5454

5555
type CTagsParser struct {
56-
tags []*types.CTag
56+
tags []*types.CTag
57+
mainFile string
5758
}
5859

59-
func (p *CTagsParser) Parse(ctagsOutput string) []*types.CTag {
60+
func (p *CTagsParser) Parse(ctagsOutput string, mainFile string) []*types.CTag {
6061
rows := strings.Split(ctagsOutput, "\n")
6162
rows = removeEmpty(rows)
6263

64+
p.mainFile = mainFile
65+
6366
for _, row := range rows {
6467
p.tags = append(p.tags, parseTag(row))
6568
}
@@ -236,7 +239,6 @@ func parseTag(row string) *types.CTag {
236239

237240
parts = parts[2:]
238241

239-
signature := ""
240242
returntype := ""
241243
for _, part := range parts {
242244
if strings.Contains(part, ":") {
@@ -253,7 +255,7 @@ func parseTag(row string) *types.CTag {
253255
case "typeref":
254256
tag.Typeref = value
255257
case "signature":
256-
signature = value
258+
tag.Signature = value
257259
case "returntype":
258260
returntype = value
259261
case "class":
@@ -265,7 +267,7 @@ func parseTag(row string) *types.CTag {
265267
}
266268
}
267269
}
268-
tag.Prototype = returntype + " " + tag.FunctionName + signature + ";"
270+
tag.Prototype = returntype + " " + tag.FunctionName + tag.Signature + ";"
269271

270272
if strings.Contains(row, "/^") && strings.Contains(row, "$/;") {
271273
tag.Code = row[strings.Index(row, "/^")+2 : strings.Index(row, "$/;")]

Diff for: src/arduino.cc/builder/ctags/ctags_parser_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func produceTags(t *testing.T, filename string) []*types.CTag {
4444
require.NoError(t, err)
4545

4646
parser := CTagsParser{}
47-
return parser.Parse(string(bytes))
47+
return parser.Parse(string(bytes), "")
4848
}
4949

5050
func TestCTagsParserShouldListPrototypes(t *testing.T) {

Diff for: src/arduino.cc/builder/ctags/ctags_to_prototypes.go

+19-13
Original file line numberDiff line numberDiff line change
@@ -48,45 +48,51 @@ func (p *CTagsParser) findLineWhereToInsertPrototypes() int {
4848
} else {
4949
return firstFunctionPointerAsArgument
5050
}
51-
} else if firstFunctionLine == -1 {
51+
} else if firstFunctionLine != -1 {
52+
return firstFunctionLine
53+
} else if firstFunctionPointerAsArgument != -1 {
5254
return firstFunctionPointerAsArgument
5355
} else {
54-
return firstFunctionLine
56+
return 0
5557
}
5658
}
5759

5860
func (p *CTagsParser) firstFunctionPointerUsedAsArgument() int {
59-
functionNames := p.collectFunctionNames()
61+
functionTags := p.collectFunctions()
6062
for _, tag := range p.tags {
61-
if functionNameUsedAsFunctionPointerIn(tag, functionNames) {
63+
if functionNameUsedAsFunctionPointerIn(tag, functionTags) {
6264
return tag.Line
6365
}
6466
}
6567
return -1
6668
}
6769

68-
func functionNameUsedAsFunctionPointerIn(tag *types.CTag, functionNames []string) bool {
69-
for _, functionName := range functionNames {
70-
if strings.Index(tag.Code, "&"+functionName) != -1 {
70+
func functionNameUsedAsFunctionPointerIn(tag *types.CTag, functionTags []*types.CTag) bool {
71+
for _, functionTag := range functionTags {
72+
if tag.Line != functionTag.Line && strings.Index(tag.Code, "&"+functionTag.FunctionName) != -1 {
73+
return true
74+
}
75+
if tag.Line != functionTag.Line && strings.Index(tag.Code, functionTag.FunctionName) != -1 &&
76+
(functionTag.Signature == "(void)" || functionTag.Signature == "()") {
7177
return true
7278
}
7379
}
7480
return false
7581
}
7682

77-
func (p *CTagsParser) collectFunctionNames() []string {
78-
names := []string{}
83+
func (p *CTagsParser) collectFunctions() []*types.CTag {
84+
functionTags := []*types.CTag{}
7985
for _, tag := range p.tags {
80-
if tag.Kind == KIND_FUNCTION {
81-
names = append(names, tag.FunctionName)
86+
if tag.Kind == KIND_FUNCTION && !tag.SkipMe {
87+
functionTags = append(functionTags, tag)
8288
}
8389
}
84-
return names
90+
return functionTags
8591
}
8692

8793
func (p *CTagsParser) firstFunctionAtLine() int {
8894
for _, tag := range p.tags {
89-
if !tagIsUnknown(tag) && isHandled(tag) && tag.Kind == KIND_FUNCTION {
95+
if !tagIsUnknown(tag) && isHandled(tag) && tag.Kind == KIND_FUNCTION && tag.Filename == p.mainFile {
9096
return tag.Line
9197
}
9298
}

Diff for: src/arduino.cc/builder/ctags/ctags_to_prototypes_test.go

+36-17
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,17 @@ import (
3838
"github.com/stretchr/testify/require"
3939
)
4040

41-
func producePrototypes(t *testing.T, filename string) ([]*types.Prototype, int) {
41+
func producePrototypes(t *testing.T, filename string, mainFile string) ([]*types.Prototype, int) {
4242
bytes, err := ioutil.ReadFile(filepath.Join("test_data", filename))
4343
require.NoError(t, err)
4444

4545
parser := &CTagsParser{}
46-
parser.Parse(string(bytes))
46+
parser.Parse(string(bytes), mainFile)
4747
return parser.GeneratePrototypes()
4848
}
4949

5050
func TestCTagsToPrototypesShouldListPrototypes(t *testing.T) {
51-
prototypes, line := producePrototypes(t, "TestCTagsParserShouldListPrototypes.txt")
51+
prototypes, line := producePrototypes(t, "TestCTagsParserShouldListPrototypes.txt", "/tmp/sketch7210316334309249705.cpp")
5252
require.Equal(t, 5, len(prototypes))
5353
require.Equal(t, "void setup();", prototypes[0].Prototype)
5454
require.Equal(t, "/tmp/sketch7210316334309249705.cpp", prototypes[0].File)
@@ -61,7 +61,7 @@ func TestCTagsToPrototypesShouldListPrototypes(t *testing.T) {
6161
}
6262

6363
func TestCTagsToPrototypesShouldListTemplates(t *testing.T) {
64-
prototypes, line := producePrototypes(t, "TestCTagsParserShouldListTemplates.txt")
64+
prototypes, line := producePrototypes(t, "TestCTagsParserShouldListTemplates.txt", "/tmp/sketch8398023134925534708.cpp")
6565

6666
require.Equal(t, 3, len(prototypes))
6767
require.Equal(t, "template <typename T> T minimum (T a, T b);", prototypes[0].Prototype)
@@ -73,7 +73,7 @@ func TestCTagsToPrototypesShouldListTemplates(t *testing.T) {
7373
}
7474

7575
func TestCTagsToPrototypesShouldListTemplates2(t *testing.T) {
76-
prototypes, line := producePrototypes(t, "TestCTagsParserShouldListTemplates2.txt")
76+
prototypes, line := producePrototypes(t, "TestCTagsParserShouldListTemplates2.txt", "/tmp/sketch463160524247569568.cpp")
7777

7878
require.Equal(t, 4, len(prototypes))
7979
require.Equal(t, "void setup();", prototypes[0].Prototype)
@@ -86,15 +86,15 @@ func TestCTagsToPrototypesShouldListTemplates2(t *testing.T) {
8686
}
8787

8888
func TestCTagsToPrototypesShouldDealWithClasses(t *testing.T) {
89-
prototypes, line := producePrototypes(t, "TestCTagsParserShouldDealWithClasses.txt")
89+
prototypes, line := producePrototypes(t, "TestCTagsParserShouldDealWithClasses.txt", "/tmp/sketch9043227824785312266.cpp")
9090

9191
require.Equal(t, 0, len(prototypes))
9292

9393
require.Equal(t, 8, line)
9494
}
9595

9696
func TestCTagsToPrototypesShouldDealWithStructs(t *testing.T) {
97-
prototypes, line := producePrototypes(t, "TestCTagsParserShouldDealWithStructs.txt")
97+
prototypes, line := producePrototypes(t, "TestCTagsParserShouldDealWithStructs.txt", "/tmp/sketch8930345717354294915.cpp")
9898

9999
require.Equal(t, 3, len(prototypes))
100100
require.Equal(t, "void setup();", prototypes[0].Prototype)
@@ -106,7 +106,7 @@ func TestCTagsToPrototypesShouldDealWithStructs(t *testing.T) {
106106
}
107107

108108
func TestCTagsToPrototypesShouldDealWithMacros(t *testing.T) {
109-
prototypes, line := producePrototypes(t, "TestCTagsParserShouldDealWithMacros.txt")
109+
prototypes, line := producePrototypes(t, "TestCTagsParserShouldDealWithMacros.txt", "/tmp/sketch5976699731718729500.cpp")
110110

111111
require.Equal(t, 5, len(prototypes))
112112
require.Equal(t, "void setup();", prototypes[0].Prototype)
@@ -120,7 +120,7 @@ func TestCTagsToPrototypesShouldDealWithMacros(t *testing.T) {
120120
}
121121

122122
func TestCTagsToPrototypesShouldDealFunctionWithDifferentSignatures(t *testing.T) {
123-
prototypes, line := producePrototypes(t, "TestCTagsParserShouldDealFunctionWithDifferentSignatures.txt")
123+
prototypes, line := producePrototypes(t, "TestCTagsParserShouldDealFunctionWithDifferentSignatures.txt", "/tmp/test260613593/preproc/ctags_target.cpp")
124124

125125
require.Equal(t, 1, len(prototypes))
126126
require.Equal(t, "boolean getBytes( byte addr, int amount );", prototypes[0].Prototype)
@@ -130,7 +130,7 @@ func TestCTagsToPrototypesShouldDealFunctionWithDifferentSignatures(t *testing.T
130130
}
131131

132132
func TestCTagsToPrototypesClassMembersAreFilteredOut(t *testing.T) {
133-
prototypes, line := producePrototypes(t, "TestCTagsParserClassMembersAreFilteredOut.txt")
133+
prototypes, line := producePrototypes(t, "TestCTagsParserClassMembersAreFilteredOut.txt", "/tmp/test834438754/preproc/ctags_target.cpp")
134134

135135
require.Equal(t, 2, len(prototypes))
136136
require.Equal(t, "void setup();", prototypes[0].Prototype)
@@ -141,7 +141,7 @@ func TestCTagsToPrototypesClassMembersAreFilteredOut(t *testing.T) {
141141
}
142142

143143
func TestCTagsToPrototypesStructWithFunctions(t *testing.T) {
144-
prototypes, line := producePrototypes(t, "TestCTagsParserStructWithFunctions.txt")
144+
prototypes, line := producePrototypes(t, "TestCTagsParserStructWithFunctions.txt", "/tmp/build7315640391316178285.tmp/preproc/ctags_target.cpp")
145145

146146
require.Equal(t, 2, len(prototypes))
147147
require.Equal(t, "void setup();", prototypes[0].Prototype)
@@ -152,7 +152,7 @@ func TestCTagsToPrototypesStructWithFunctions(t *testing.T) {
152152
}
153153

154154
func TestCTagsToPrototypesDefaultArguments(t *testing.T) {
155-
prototypes, line := producePrototypes(t, "TestCTagsParserDefaultArguments.txt")
155+
prototypes, line := producePrototypes(t, "TestCTagsParserDefaultArguments.txt", "/tmp/test179252494/preproc/ctags_target.cpp")
156156

157157
require.Equal(t, 3, len(prototypes))
158158
require.Equal(t, "void test(int x = 1);", prototypes[0].Prototype)
@@ -164,7 +164,7 @@ func TestCTagsToPrototypesDefaultArguments(t *testing.T) {
164164
}
165165

166166
func TestCTagsToPrototypesNamespace(t *testing.T) {
167-
prototypes, line := producePrototypes(t, "TestCTagsParserNamespace.txt")
167+
prototypes, line := producePrototypes(t, "TestCTagsParserNamespace.txt", "/tmp/test030883150/preproc/ctags_target.cpp")
168168

169169
require.Equal(t, 2, len(prototypes))
170170
require.Equal(t, "void setup();", prototypes[0].Prototype)
@@ -175,7 +175,7 @@ func TestCTagsToPrototypesNamespace(t *testing.T) {
175175
}
176176

177177
func TestCTagsToPrototypesStatic(t *testing.T) {
178-
prototypes, line := producePrototypes(t, "TestCTagsParserStatic.txt")
178+
prototypes, line := producePrototypes(t, "TestCTagsParserStatic.txt", "/tmp/test542833488/preproc/ctags_target.cpp")
179179

180180
require.Equal(t, 3, len(prototypes))
181181
require.Equal(t, "void setup();", prototypes[0].Prototype)
@@ -188,7 +188,7 @@ func TestCTagsToPrototypesStatic(t *testing.T) {
188188
}
189189

190190
func TestCTagsToPrototypesFunctionPointer(t *testing.T) {
191-
prototypes, line := producePrototypes(t, "TestCTagsParserFunctionPointer.txt")
191+
prototypes, line := producePrototypes(t, "TestCTagsParserFunctionPointer.txt", "/tmp/test547238273/preproc/ctags_target.cpp")
192192

193193
require.Equal(t, 3, len(prototypes))
194194
require.Equal(t, "void t1Callback();", prototypes[0].Prototype)
@@ -200,7 +200,7 @@ func TestCTagsToPrototypesFunctionPointer(t *testing.T) {
200200
}
201201

202202
func TestCTagsToPrototypesFunctionPointers(t *testing.T) {
203-
prototypes, line := producePrototypes(t, "TestCTagsParserFunctionPointers.txt")
203+
prototypes, line := producePrototypes(t, "TestCTagsParserFunctionPointers.txt", "/tmp/test907446433/preproc/ctags_target.cpp")
204204
require.Equal(t, 2, len(prototypes))
205205
require.Equal(t, "void setup();", prototypes[0].Prototype)
206206
require.Equal(t, "/tmp/test907446433/preproc/ctags_target.cpp", prototypes[0].File)
@@ -209,11 +209,30 @@ func TestCTagsToPrototypesFunctionPointers(t *testing.T) {
209209
require.Equal(t, 2, line)
210210
}
211211

212+
func TestCTagsToPrototypesFunctionPointersNoIndirect(t *testing.T) {
213+
prototypes, line := producePrototypes(t, "TestCTagsParserFunctionPointersNoIndirect.txt", "/tmp/test547238273/preproc/bug_callback.ino")
214+
require.Equal(t, 5, len(prototypes))
215+
require.Equal(t, "void setup();", prototypes[0].Prototype)
216+
require.Equal(t, "/tmp/test547238273/preproc/bug_callback.ino", prototypes[0].File)
217+
require.Equal(t, "void loop();", prototypes[1].Prototype)
218+
219+
require.Equal(t, 10, line)
220+
}
221+
212222
func TestCTagsRunnerSketchWithClassFunction(t *testing.T) {
213-
prototypes, _ := producePrototypes(t, "TestCTagsRunnerSketchWithClassFunction.txt")
223+
prototypes, _ := producePrototypes(t, "TestCTagsRunnerSketchWithClassFunction.txt", "/home/megabug/Workspace/arduino-builder/src/arduino.cc/builder/test/sketch_class_function/sketch_class_function.ino")
214224

215225
require.Equal(t, 3, len(prototypes))
216226
require.Equal(t, "void setup();", prototypes[0].Prototype)
217227
require.Equal(t, "void loop();", prototypes[1].Prototype)
218228
require.Equal(t, "void asdf();", prototypes[2].Prototype)
219229
}
230+
231+
func TestCTagsRunnerSketchWithMultiFile(t *testing.T) {
232+
prototypes, line := producePrototypes(t, "TestCTagsRunnerSketchWithMultifile.txt", "/tmp/apUNI8a/main.ino")
233+
234+
require.Equal(t, 0, line)
235+
require.Equal(t, "void A7105_Setup();", prototypes[0].Prototype)
236+
require.Equal(t, "void A7105_Reset();", prototypes[1].Prototype)
237+
require.Equal(t, "int A7105_calibrate_VCB(uint8_t channel);", prototypes[2].Prototype)
238+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
BUG /tmp/test547238273/preproc/bug_callback.ino /^ public: BUG(void (*fn)(void)) {}$/;" kind:function line:6 class:BUG signature:(void (*fn)(void))
2+
b /tmp/test547238273/preproc/bug_callback.ino /^BUG b(makeItBreak); \/\/this will break$/;" kind:prototype line:10 signature:(makeItBreak)returntype:BUG
3+
setup /tmp/test547238273/preproc/bug_callback.ino /^void setup() {$/;" kind:function line:12 signature:() returntype:void
4+
loop /tmp/test547238273/preproc/bug_callback.ino /^void loop() {}$/;" kind:function line:16 signature:() returntype:void
5+
makeItBreak /tmp/test547238273/preproc/bug_callback.ino /^void makeItBreak() {}$/;" kind:function line:18 signature:() returntype:void
6+
caller /tmp/test547238273/preproc/bug_callback.ino /^void caller(int (*cc)(int ),int a) {$/;" kind:function line:20 signature:(int (*cc)(int ),int a) returntype:void
7+
blub /tmp/test547238273/preproc/bug_callback.ino /^int blub(int a) {$/;" kind:function line:24 signature:(int a) returntype:int

0 commit comments

Comments
 (0)