From b0fb652d7fbd8e4ab7a850207d282de3b168ff79 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 7 Apr 2016 18:24:38 +0200 Subject: [PATCH 1/4] Avoid using whole ctags_target_for_gcc_minus_e for prototype generation Ctags is FULL of bugs on c++ parsing (and c++ syntax is a nightmare), sketches are usually way more simple (and easier to debug). Using a simplified version of the ctags_target_for_gcc_minus_e file which only contains preprocessor directives and the sketch lines helps avoiding most ctags subtle bugs. Signed-off-by: Martino Facchin --- .../builder/ctags_target_file_saver.go | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/arduino.cc/builder/ctags_target_file_saver.go b/src/arduino.cc/builder/ctags_target_file_saver.go index 0f3277ca..36c30969 100644 --- a/src/arduino.cc/builder/ctags_target_file_saver.go +++ b/src/arduino.cc/builder/ctags_target_file_saver.go @@ -34,6 +34,8 @@ import ( "arduino.cc/builder/types" "arduino.cc/builder/utils" "path/filepath" + "strconv" + "strings" ) type CTagsTargetFileSaver struct { @@ -50,6 +52,12 @@ func (s *CTagsTargetFileSaver) Run(ctx *types.Context) error { return i18n.WrapError(err) } + // drop every line which is not part of user sketch or a define/ifdef/endif/etc + var searchSlice []string + searchSlice = append(searchSlice, filepath.Dir(ctx.SketchLocation)) + searchSlice = append(searchSlice, filepath.Dir(ctx.BuildPath)) + source = saveLinesContainingDirectivesAndSketch(source, searchSlice) + ctagsTargetFilePath := filepath.Join(preprocPath, s.TargetFileName) err = utils.WriteFile(ctagsTargetFilePath, source) if err != nil { @@ -60,3 +68,52 @@ func (s *CTagsTargetFileSaver) Run(ctx *types.Context) error { return nil } + +func saveLinesContainingDirectivesAndSketch(src string, tofind []string) string { + lines := strings.Split(src, "\n") + + saveLine := false + minimizedString := "" + + for _, line := range lines { + if saveLine || startsWithHashtag(line) { + minimizedString += line + "\n" + } + if containsAny(line, tofind) && isPreprocessorLineMarker(line) { + saveLine = true + } + if saveLine && !containsAny(line, tofind) && isPreprocessorLineMarker(line) { + saveLine = false + } + } + return minimizedString +} + +func containsAny(src string, tofind []string) bool { + for _, str := range tofind { + if strings.Contains(src, str) { + return true + } + } + return false +} + +func startsWithHashtag(src string) bool { + trimmedStr := strings.TrimSpace(src) + if len(trimmedStr) > 0 && trimmedStr[0] == '#' { + return true + } + return false +} + +func isPreprocessorLineMarker(src string) bool { + trimmedStr := strings.TrimSpace(src) + splittedStr := strings.Split(trimmedStr, " ") + if len(splittedStr) > 2 && splittedStr[0] == "#" { + _, err := strconv.Atoi(splittedStr[1]) + if err == nil { + return true + } + } + return false +} From 033d21e228bb22b8aa8e5a431be2db1c321a66bb Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 3 May 2016 11:36:23 +0200 Subject: [PATCH 2/4] don't consider already skipped tags as candidates when searching for duplicates Signed-off-by: Martino Facchin --- src/arduino.cc/builder/ctags/ctags_parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arduino.cc/builder/ctags/ctags_parser.go b/src/arduino.cc/builder/ctags/ctags_parser.go index 55497155..318c679b 100644 --- a/src/arduino.cc/builder/ctags/ctags_parser.go +++ b/src/arduino.cc/builder/ctags/ctags_parser.go @@ -130,7 +130,7 @@ func removeDuplicate(tags []*types.CTag) { definedPrototypes := make(map[string]bool) for _, tag := range tags { - if !definedPrototypes[tag.Prototype] { + if !definedPrototypes[tag.Prototype] && tag.SkipMe == false { definedPrototypes[tag.Prototype] = true } else { tag.SkipMe = true From 95d67a3454aea2fb8689050f6bd8c40cde471bdc Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 3 May 2016 12:16:17 +0200 Subject: [PATCH 3/4] CtagsFileSaver: Look for the hashtag as character, not string TestCTagsRunner* use the #line directive generated file as source instead than # $linenumber. Searching fot the '#' as first char make tests passing Signed-off-by: Martino Facchin --- src/arduino.cc/builder/ctags_target_file_saver.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/arduino.cc/builder/ctags_target_file_saver.go b/src/arduino.cc/builder/ctags_target_file_saver.go index 36c30969..5df0d40d 100644 --- a/src/arduino.cc/builder/ctags_target_file_saver.go +++ b/src/arduino.cc/builder/ctags_target_file_saver.go @@ -79,10 +79,10 @@ func saveLinesContainingDirectivesAndSketch(src string, tofind []string) string if saveLine || startsWithHashtag(line) { minimizedString += line + "\n" } - if containsAny(line, tofind) && isPreprocessorLineMarker(line) { + if containsAny(line, tofind) && isLineMarker(line) { saveLine = true } - if saveLine && !containsAny(line, tofind) && isPreprocessorLineMarker(line) { + if saveLine && !containsAny(line, tofind) && isLineMarker(line) { saveLine = false } } @@ -106,10 +106,10 @@ func startsWithHashtag(src string) bool { return false } -func isPreprocessorLineMarker(src string) bool { +func isLineMarker(src string) bool { trimmedStr := strings.TrimSpace(src) splittedStr := strings.Split(trimmedStr, " ") - if len(splittedStr) > 2 && splittedStr[0] == "#" { + if len(splittedStr) > 2 && splittedStr[0][0] == '#' { _, err := strconv.Atoi(splittedStr[1]) if err == nil { return true From 7b6fbf5bbf6551054edbc97463617ed1f5506407 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 4 May 2016 11:33:41 +0200 Subject: [PATCH 4/4] add test to target issue #140 Signed-off-by: Martino Facchin --- .../builder/test/ctags_to_prototypes_test.go | 52 +++++++++++++++++++ .../sketch_class_function.ino | 8 +++ 2 files changed, 60 insertions(+) create mode 100644 src/arduino.cc/builder/test/sketch_with_class/sketch_class_function.ino diff --git a/src/arduino.cc/builder/test/ctags_to_prototypes_test.go b/src/arduino.cc/builder/test/ctags_to_prototypes_test.go index ca1a2a6b..55dd7abe 100644 --- a/src/arduino.cc/builder/test/ctags_to_prototypes_test.go +++ b/src/arduino.cc/builder/test/ctags_to_prototypes_test.go @@ -30,10 +30,13 @@ package test import ( + "arduino.cc/builder" + "arduino.cc/builder/constants" "arduino.cc/builder/ctags" "arduino.cc/builder/types" "github.com/stretchr/testify/require" "io/ioutil" + "os" "path/filepath" "testing" ) @@ -459,3 +462,52 @@ func TestCTagsToPrototypesFunctionPointers(t *testing.T) { require.Equal(t, 2, ctx.PrototypesLineWhereToInsert) } + +func TestCTagsRunnerSketchWithClassFunction(t *testing.T) { + DownloadCoresAndToolsAndLibraries(t) + + sketchLocation := Abs(t, filepath.Join("sketch_with_class", "sketch_class_function.ino")) + + ctx := &types.Context{ + HardwareFolders: []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"}, + ToolsFolders: []string{"downloaded_tools"}, + BuiltInLibrariesFolders: []string{"downloaded_libraries"}, + OtherLibrariesFolders: []string{"libraries"}, + SketchLocation: sketchLocation, + FQBN: "arduino:avr:leonardo", + ArduinoAPIVersion: "10600", + Verbose: true, + } + + buildPath := SetupBuildPath(t, ctx) + defer os.RemoveAll(buildPath) + + commands := []types.Command{ + + &builder.ContainerSetupHardwareToolsLibsSketchAndProps{}, + + &builder.ContainerMergeCopySketchFiles{}, + + &builder.ContainerFindIncludes{}, + + &builder.PrintUsedLibrariesIfVerbose{}, + &builder.WarnAboutArchIncompatibleLibraries{}, + &builder.CTagsTargetFileSaver{Source: &ctx.Source, TargetFileName: constants.FILE_CTAGS_TARGET}, + &ctags.CTagsRunner{}, + &ctags.CTagsParser{}, + &CollectCtagsFromPreprocSource{}, + &ctags.CTagsToPrototypes{}, + } + + for _, command := range commands { + err := command.Run(ctx) + NoError(t, err) + } + + prototypes := ctx.Prototypes + + require.Equal(t, 3, len(prototypes)) + require.Equal(t, "void setup();", prototypes[0].Prototype) + require.Equal(t, "void loop();", prototypes[1].Prototype) + require.Equal(t, "void asdf();", prototypes[2].Prototype) +} diff --git a/src/arduino.cc/builder/test/sketch_with_class/sketch_class_function.ino b/src/arduino.cc/builder/test/sketch_with_class/sketch_class_function.ino new file mode 100644 index 00000000..45250090 --- /dev/null +++ b/src/arduino.cc/builder/test/sketch_with_class/sketch_class_function.ino @@ -0,0 +1,8 @@ +class test { + void asdf() {} +}; +void setup() { + asdf(); +} +void loop() {} +void asdf() {} \ No newline at end of file