Skip to content

Commit a25b7e8

Browse files
author
Federico Fissore
committed
Introducing types.Prototype: useful for carrying more data about original
ctags output, including function name Function name is used in compare_prototypes_from_source_and_preproc_source to understand if a function is part of preprocessed output. Also, prototype from preprocessed output is used instead of that coming from ctags on plain sketch, as ctags may be fooled by #define Fixes #28 Signed-off-by: Federico Fissore <[email protected]>
1 parent 91c1fe1 commit a25b7e8

File tree

10 files changed

+189
-71
lines changed

10 files changed

+189
-71
lines changed

src/arduino.cc/builder/compare_prototypes_from_source_and_preproc_source.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,20 @@ package builder
3131

3232
import (
3333
"arduino.cc/builder/constants"
34+
"arduino.cc/builder/types"
3435
"arduino.cc/builder/utils"
3536
)
3637

3738
type ComparePrototypesFromSourceAndPreprocSource struct{}
3839

3940
func (s *ComparePrototypesFromSourceAndPreprocSource) Run(context map[string]interface{}) error {
40-
prototypesOfSource := context[constants.CTX_PROTOTYPES_OF_SOURCE].([]string)
41-
prototypesOfPreprocSource := context[constants.CTX_PROTOTYPES_OF_PREPROC_SOURCE].([]string)
41+
prototypesOfSource := context[constants.CTX_PROTOTYPES_OF_SOURCE].([]*types.Prototype)
42+
prototypesOfPreprocSource := context[constants.CTX_PROTOTYPES_OF_PREPROC_SOURCE].([]*types.Prototype)
4243

43-
var actualPrototypes []string
44-
for _, prototypeOfSource := range prototypesOfSource {
45-
if utils.SliceContains(prototypesOfPreprocSource, prototypeOfSource) {
46-
actualPrototypes = append(actualPrototypes, prototypeOfSource)
44+
actualPrototypes := []*types.Prototype{}
45+
for _, prototypeOfPreprocSource := range prototypesOfPreprocSource {
46+
if utils.SliceContainsPrototype(prototypesOfSource, prototypeOfPreprocSource) {
47+
actualPrototypes = append(actualPrototypes, prototypeOfPreprocSource)
4748
}
4849
}
4950

src/arduino.cc/builder/ctags_parser.go

+13-6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ package builder
3131

3232
import (
3333
"arduino.cc/builder/constants"
34+
"arduino.cc/builder/types"
3435
"arduino.cc/builder/utils"
3536
"strconv"
3637
"strings"
@@ -83,18 +84,24 @@ func (s *CTagsParser) Run(context map[string]interface{}) error {
8384
context[constants.CTX_FIRST_FUNCTION_AT_LINE] = line
8485
}
8586

86-
var prototypes []string
87-
for _, tag := range tags {
88-
if tag[FIELD_SKIP] != "true" {
89-
prototypes = append(prototypes, tag[KIND_PROTOTYPE])
90-
}
91-
}
87+
prototypes := toPrototypes(tags)
9288

9389
context[s.PrototypesField] = prototypes
9490

9591
return nil
9692
}
9793

94+
func toPrototypes(tags []map[string]string) []*types.Prototype {
95+
prototypes := []*types.Prototype{}
96+
for _, tag := range tags {
97+
if tag[FIELD_SKIP] != "true" {
98+
ctag := types.Prototype{FunctionName: tag[FIELD_FUNCTION_NAME], Prototype: tag[KIND_PROTOTYPE], Fields: tag}
99+
prototypes = append(prototypes, &ctag)
100+
}
101+
}
102+
return prototypes
103+
}
104+
98105
func addPrototypes(tags []map[string]string) []map[string]string {
99106
for _, tag := range tags {
100107
addPrototype(tag)

src/arduino.cc/builder/prototypes_adder.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ package builder
3131

3232
import (
3333
"arduino.cc/builder/constants"
34+
"arduino.cc/builder/types"
3435
"arduino.cc/builder/utils"
3536
"strconv"
3637
"strings"
@@ -55,7 +56,7 @@ func (s *PrototypesAdder) Run(context map[string]interface{}) error {
5556
if firstFunctionLine > 1 {
5657
firstFunctionLine -= context[constants.CTX_LINE_OFFSET].(int)
5758
}
58-
prototypeSection := composePrototypeSection(firstFunctionLine, context[constants.CTX_PROTOTYPES].([]string))
59+
prototypeSection := composePrototypeSection(firstFunctionLine, context[constants.CTX_PROTOTYPES].([]*types.Prototype))
5960
context[constants.CTX_PROTOTYPE_SECTION] = prototypeSection
6061
source = source[:firstFunctionChar] + prototypeSection + source[firstFunctionChar:]
6162

@@ -68,19 +69,27 @@ func (s *PrototypesAdder) Run(context map[string]interface{}) error {
6869
return nil
6970
}
7071

71-
func composePrototypeSection(line int, prototypes []string) string {
72+
func composePrototypeSection(line int, prototypes []*types.Prototype) string {
7273
if len(prototypes) == 0 {
7374
return constants.EMPTY_STRING
7475
}
7576

76-
str := strings.Join(prototypes, "\n") + "\n"
77+
str := joinPrototypes(prototypes)
7778
str += "#line "
7879
str += strconv.Itoa(line)
7980
str += "\n"
8081

8182
return str
8283
}
8384

85+
func joinPrototypes(prototypes []*types.Prototype) string {
86+
join := ""
87+
for _, proto := range prototypes {
88+
join = join + proto.Prototype + "\n"
89+
}
90+
return join
91+
}
92+
8493
func composeIncludeArduinoSection() string {
8594
str := "#include <Arduino.h>\n"
8695
str += "#line 1\n"

src/arduino.cc/builder/test/ctags_parser_test.go

+38-37
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ package test
3232
import (
3333
"arduino.cc/builder"
3434
"arduino.cc/builder/constants"
35+
"arduino.cc/builder/types"
3536
"github.com/stretchr/testify/require"
3637
"io/ioutil"
3738
"path/filepath"
@@ -49,14 +50,14 @@ func TestCTagsParserShouldListPrototypes(t *testing.T) {
4950
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
5051
ctagsParser.Run(context)
5152

52-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
53+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
5354

5455
require.Equal(t, 5, len(prototypes))
55-
require.Equal(t, "void setup();", prototypes[0])
56-
require.Equal(t, "void loop();", prototypes[1])
57-
require.Equal(t, "void digitalCommand(YunClient client);", prototypes[2])
58-
require.Equal(t, "void analogCommand(YunClient client);", prototypes[3])
59-
require.Equal(t, "void modeCommand(YunClient client);", prototypes[4])
56+
require.Equal(t, "void setup();", prototypes[0].Prototype)
57+
require.Equal(t, "void loop();", prototypes[1].Prototype)
58+
require.Equal(t, "void digitalCommand(YunClient client);", prototypes[2].Prototype)
59+
require.Equal(t, "void analogCommand(YunClient client);", prototypes[3].Prototype)
60+
require.Equal(t, "void modeCommand(YunClient client);", prototypes[4].Prototype)
6061
}
6162

6263
func TestCTagsParserShouldListTemplates(t *testing.T) {
@@ -70,12 +71,12 @@ func TestCTagsParserShouldListTemplates(t *testing.T) {
7071
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
7172
ctagsParser.Run(context)
7273

73-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
74+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
7475

7576
require.Equal(t, 3, len(prototypes))
76-
require.Equal(t, "template <typename T> T minimum (T a, T b);", prototypes[0])
77-
require.Equal(t, "void setup();", prototypes[1])
78-
require.Equal(t, "void loop();", prototypes[2])
77+
require.Equal(t, "template <typename T> T minimum (T a, T b);", prototypes[0].Prototype)
78+
require.Equal(t, "void setup();", prototypes[1].Prototype)
79+
require.Equal(t, "void loop();", prototypes[2].Prototype)
7980
}
8081

8182
func TestCTagsParserShouldListTemplates2(t *testing.T) {
@@ -89,13 +90,13 @@ func TestCTagsParserShouldListTemplates2(t *testing.T) {
8990
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
9091
ctagsParser.Run(context)
9192

92-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
93+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
9394

9495
require.Equal(t, 4, len(prototypes))
95-
require.Equal(t, "void setup();", prototypes[0])
96-
require.Equal(t, "void loop();", prototypes[1])
97-
require.Equal(t, "template <class T> int SRAM_writeAnything(int ee, const T& value);", prototypes[2])
98-
require.Equal(t, "template <class T> int SRAM_readAnything(int ee, T& value);", prototypes[3])
96+
require.Equal(t, "void setup();", prototypes[0].Prototype)
97+
require.Equal(t, "void loop();", prototypes[1].Prototype)
98+
require.Equal(t, "template <class T> int SRAM_writeAnything(int ee, const T& value);", prototypes[2].Prototype)
99+
require.Equal(t, "template <class T> int SRAM_readAnything(int ee, T& value);", prototypes[3].Prototype)
99100
}
100101

101102
func TestCTagsParserShouldDealWithClasses(t *testing.T) {
@@ -109,7 +110,7 @@ func TestCTagsParserShouldDealWithClasses(t *testing.T) {
109110
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
110111
ctagsParser.Run(context)
111112

112-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
113+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
113114

114115
require.Equal(t, 0, len(prototypes))
115116
}
@@ -125,12 +126,12 @@ func TestCTagsParserShouldDealWithStructs(t *testing.T) {
125126
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
126127
ctagsParser.Run(context)
127128

128-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
129+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
129130

130131
require.Equal(t, 3, len(prototypes))
131-
require.Equal(t, "void setup();", prototypes[0])
132-
require.Equal(t, "void loop();", prototypes[1])
133-
require.Equal(t, "void dostuff(A_NEW_TYPE * bar);", prototypes[2])
132+
require.Equal(t, "void setup();", prototypes[0].Prototype)
133+
require.Equal(t, "void loop();", prototypes[1].Prototype)
134+
require.Equal(t, "void dostuff(A_NEW_TYPE * bar);", prototypes[2].Prototype)
134135
}
135136

136137
func TestCTagsParserShouldDealWithMacros(t *testing.T) {
@@ -144,14 +145,14 @@ func TestCTagsParserShouldDealWithMacros(t *testing.T) {
144145
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
145146
ctagsParser.Run(context)
146147

147-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
148+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
148149

149150
require.Equal(t, 5, len(prototypes))
150-
require.Equal(t, "void setup();", prototypes[0])
151-
require.Equal(t, "void loop();", prototypes[1])
152-
require.Equal(t, "void debug();", prototypes[2])
153-
require.Equal(t, "void disabledIsDefined();", prototypes[3])
154-
require.Equal(t, "int useMyType(MyType type);", prototypes[4])
151+
require.Equal(t, "void setup();", prototypes[0].Prototype)
152+
require.Equal(t, "void loop();", prototypes[1].Prototype)
153+
require.Equal(t, "void debug();", prototypes[2].Prototype)
154+
require.Equal(t, "void disabledIsDefined();", prototypes[3].Prototype)
155+
require.Equal(t, "int useMyType(MyType type);", prototypes[4].Prototype)
155156
}
156157

157158
func TestCTagsParserShouldDealFunctionWithDifferentSignatures(t *testing.T) {
@@ -165,10 +166,10 @@ func TestCTagsParserShouldDealFunctionWithDifferentSignatures(t *testing.T) {
165166
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
166167
ctagsParser.Run(context)
167168

168-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
169+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
169170

170171
require.Equal(t, 1, len(prototypes))
171-
require.Equal(t, "boolean getBytes( byte addr, int amount );", prototypes[0])
172+
require.Equal(t, "boolean getBytes( byte addr, int amount );", prototypes[0].Prototype)
172173
}
173174

174175
func TestCTagsParserClassMembersAreFilteredOut(t *testing.T) {
@@ -182,11 +183,11 @@ func TestCTagsParserClassMembersAreFilteredOut(t *testing.T) {
182183
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
183184
ctagsParser.Run(context)
184185

185-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
186+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
186187

187188
require.Equal(t, 2, len(prototypes))
188-
require.Equal(t, "void setup();", prototypes[0])
189-
require.Equal(t, "void loop();", prototypes[1])
189+
require.Equal(t, "void setup();", prototypes[0].Prototype)
190+
require.Equal(t, "void loop();", prototypes[1].Prototype)
190191
}
191192

192193
func TestCTagsParserStructWithFunctions(t *testing.T) {
@@ -200,11 +201,11 @@ func TestCTagsParserStructWithFunctions(t *testing.T) {
200201
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
201202
ctagsParser.Run(context)
202203

203-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
204+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
204205

205206
require.Equal(t, 2, len(prototypes))
206-
require.Equal(t, "void setup();", prototypes[0])
207-
require.Equal(t, "void loop();", prototypes[1])
207+
require.Equal(t, "void setup();", prototypes[0].Prototype)
208+
require.Equal(t, "void loop();", prototypes[1].Prototype)
208209
}
209210

210211
func TestCTagsParserDefaultArguments(t *testing.T) {
@@ -218,9 +219,9 @@ func TestCTagsParserDefaultArguments(t *testing.T) {
218219
ctagsParser := builder.CTagsParser{PrototypesField: constants.CTX_PROTOTYPES}
219220
ctagsParser.Run(context)
220221

221-
prototypes := context[constants.CTX_PROTOTYPES].([]string)
222+
prototypes := context[constants.CTX_PROTOTYPES].([]*types.Prototype)
222223

223224
require.Equal(t, 2, len(prototypes))
224-
require.Equal(t, "void setup();", prototypes[0])
225-
require.Equal(t, "void loop();", prototypes[1])
225+
require.Equal(t, "void setup();", prototypes[0].Prototype)
226+
require.Equal(t, "void loop();", prototypes[1].Prototype)
226227
}

src/arduino.cc/builder/test/prototypes_adder_test.go

+41-1
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ func TestPrototypesAdderSketchWithInlineFunction(t *testing.T) {
537537
context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_inline_function", "sketch.ino")
538538
context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600"
539539
context[constants.CTX_LIBRARIES_FOLDERS] = []string{"libraries", "downloaded_libraries"}
540-
context[constants.CTX_VERBOSE] = true
540+
context[constants.CTX_VERBOSE] = false
541541

542542
commands := []types.Command{
543543
&builder.SetupHumanLoggerIfMissing{},
@@ -562,3 +562,43 @@ func TestPrototypesAdderSketchWithInlineFunction(t *testing.T) {
562562
require.Equal(t, "#include <Arduino.h>\n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string))
563563
require.Equal(t, "void setup();\nvoid loop();\nshort unsigned int testInt();\nint8_t testInline();\nuint8_t testAttribute();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string))
564564
}
565+
566+
func TestPrototypesAdderSketchWithFunctionSignatureInsideIFDEF(t *testing.T) {
567+
DownloadCoresAndToolsAndLibraries(t)
568+
569+
context := make(map[string]interface{})
570+
571+
_ = SetupBuildPath(t, context)
572+
//defer os.RemoveAll(buildPath)
573+
574+
context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"}
575+
context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"}
576+
context[constants.CTX_FQBN] = "arduino:avr:leonardo"
577+
context[constants.CTX_SKETCH_LOCATION] = filepath.Join("sketch_with_function_signature_inside_ifdef", "sketch.ino")
578+
context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600"
579+
context[constants.CTX_LIBRARIES_FOLDERS] = []string{"libraries", "downloaded_libraries"}
580+
context[constants.CTX_VERBOSE] = true
581+
582+
commands := []types.Command{
583+
&builder.SetupHumanLoggerIfMissing{},
584+
585+
&builder.ContainerSetupHardwareToolsLibsSketchAndProps{},
586+
587+
&builder.ContainerMergeCopySketchFiles{},
588+
589+
&builder.ContainerFindIncludes{},
590+
591+
&builder.PrintUsedLibrariesIfVerbose{},
592+
&builder.WarnAboutArchIncompatibleLibraries{},
593+
594+
&builder.ContainerAddPrototypes{},
595+
}
596+
597+
for _, command := range commands {
598+
err := command.Run(context)
599+
NoError(t, err)
600+
}
601+
602+
require.Equal(t, "#include <Arduino.h>\n#line 1\n", context[constants.CTX_INCLUDE_SECTION].(string))
603+
require.Equal(t, "void setup();\nvoid loop();\nint8_t adalight();\n#line 1\n", context[constants.CTX_PROTOTYPE_SECTION].(string))
604+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
void setup() {}
2+
3+
void loop() {
4+
// Visualize leds via Adalight
5+
int8_t newData = adalight();
6+
7+
}
8+
9+
10+
//#define ADALIGHT_USE_TEMPLATE
11+
12+
#ifdef ADALIGHT_USE_TEMPLATE
13+
int16_t adalight()
14+
#else
15+
int8_t adalight()
16+
#endif
17+
{
18+
// Flag if the leds got a new frame that should be updated
19+
return 0;
20+
}

src/arduino.cc/builder/types/accessories.go

-10
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,6 @@ func (h *UniqueStringQueue) Empty() bool {
5252
return h.Len() == 0
5353
}
5454

55-
// duplication of utils.SliceContains! Thanks golang! Why? Because you can't have import cycles, so types cannot import from utils because utils already imports from types
56-
func sliceContains(slice []string, target string) bool {
57-
for _, value := range slice {
58-
if value == target {
59-
return true
60-
}
61-
}
62-
return false
63-
}
64-
6555
type LibraryResolutionResult struct {
6656
Library *Library
6757
NotUsedLibraries []*Library

0 commit comments

Comments
 (0)