Skip to content

Fix prototypes line insertion logic #221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/arduino.cc/builder/ctags/ctags_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,16 @@ var KNOWN_TAG_KINDS = map[string]bool{
}

type CTagsParser struct {
tags []*types.CTag
tags []*types.CTag
mainFile string
}

func (p *CTagsParser) Parse(ctagsOutput string) []*types.CTag {
func (p *CTagsParser) Parse(ctagsOutput string, mainFile string) []*types.CTag {
rows := strings.Split(ctagsOutput, "\n")
rows = removeEmpty(rows)

p.mainFile = mainFile

for _, row := range rows {
p.tags = append(p.tags, parseTag(row))
}
Expand Down Expand Up @@ -236,7 +239,6 @@ func parseTag(row string) *types.CTag {

parts = parts[2:]

signature := ""
returntype := ""
for _, part := range parts {
if strings.Contains(part, ":") {
Expand All @@ -253,7 +255,7 @@ func parseTag(row string) *types.CTag {
case "typeref":
tag.Typeref = value
case "signature":
signature = value
tag.Signature = value
case "returntype":
returntype = value
case "class":
Expand All @@ -265,7 +267,7 @@ func parseTag(row string) *types.CTag {
}
}
}
tag.Prototype = returntype + " " + tag.FunctionName + signature + ";"
tag.Prototype = returntype + " " + tag.FunctionName + tag.Signature + ";"

if strings.Contains(row, "/^") && strings.Contains(row, "$/;") {
tag.Code = row[strings.Index(row, "/^")+2 : strings.Index(row, "$/;")]
Expand Down
2 changes: 1 addition & 1 deletion src/arduino.cc/builder/ctags/ctags_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func produceTags(t *testing.T, filename string) []*types.CTag {
require.NoError(t, err)

parser := CTagsParser{}
return parser.Parse(string(bytes))
return parser.Parse(string(bytes), "")
}

func TestCTagsParserShouldListPrototypes(t *testing.T) {
Expand Down
32 changes: 19 additions & 13 deletions src/arduino.cc/builder/ctags/ctags_to_prototypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,45 +48,51 @@ func (p *CTagsParser) findLineWhereToInsertPrototypes() int {
} else {
return firstFunctionPointerAsArgument
}
} else if firstFunctionLine == -1 {
} else if firstFunctionLine != -1 {
return firstFunctionLine
} else if firstFunctionPointerAsArgument != -1 {
return firstFunctionPointerAsArgument
} else {
return firstFunctionLine
return 0
}
}

func (p *CTagsParser) firstFunctionPointerUsedAsArgument() int {
functionNames := p.collectFunctionNames()
functionTags := p.collectFunctions()
for _, tag := range p.tags {
if functionNameUsedAsFunctionPointerIn(tag, functionNames) {
if functionNameUsedAsFunctionPointerIn(tag, functionTags) {
return tag.Line
}
}
return -1
}

func functionNameUsedAsFunctionPointerIn(tag *types.CTag, functionNames []string) bool {
for _, functionName := range functionNames {
if strings.Index(tag.Code, "&"+functionName) != -1 {
func functionNameUsedAsFunctionPointerIn(tag *types.CTag, functionTags []*types.CTag) bool {
for _, functionTag := range functionTags {
if tag.Line != functionTag.Line && strings.Index(tag.Code, "&"+functionTag.FunctionName) != -1 {
return true
}
if tag.Line != functionTag.Line && strings.Index(tag.Code, functionTag.FunctionName) != -1 &&
(functionTag.Signature == "(void)" || functionTag.Signature == "()") {
return true
}
}
return false
}

func (p *CTagsParser) collectFunctionNames() []string {
names := []string{}
func (p *CTagsParser) collectFunctions() []*types.CTag {
functionTags := []*types.CTag{}
for _, tag := range p.tags {
if tag.Kind == KIND_FUNCTION {
names = append(names, tag.FunctionName)
if tag.Kind == KIND_FUNCTION && !tag.SkipMe {
functionTags = append(functionTags, tag)
}
}
return names
return functionTags
}

func (p *CTagsParser) firstFunctionAtLine() int {
for _, tag := range p.tags {
if !tagIsUnknown(tag) && isHandled(tag) && tag.Kind == KIND_FUNCTION {
if !tagIsUnknown(tag) && isHandled(tag) && tag.Kind == KIND_FUNCTION && tag.Filename == p.mainFile {
return tag.Line
}
}
Expand Down
53 changes: 36 additions & 17 deletions src/arduino.cc/builder/ctags/ctags_to_prototypes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ import (
"github.com/stretchr/testify/require"
)

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

parser := &CTagsParser{}
parser.Parse(string(bytes))
parser.Parse(string(bytes), mainFile)
return parser.GeneratePrototypes()
}

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

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

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

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

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

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

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

require.Equal(t, 8, line)
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

func TestCTagsToPrototypesFunctionPointersNoIndirect(t *testing.T) {
prototypes, line := producePrototypes(t, "TestCTagsParserFunctionPointersNoIndirect.txt", "/tmp/test547238273/preproc/bug_callback.ino")
require.Equal(t, 5, len(prototypes))
require.Equal(t, "void setup();", prototypes[0].Prototype)
require.Equal(t, "/tmp/test547238273/preproc/bug_callback.ino", prototypes[0].File)
require.Equal(t, "void loop();", prototypes[1].Prototype)

require.Equal(t, 10, line)
}

func TestCTagsRunnerSketchWithClassFunction(t *testing.T) {
prototypes, _ := producePrototypes(t, "TestCTagsRunnerSketchWithClassFunction.txt")
prototypes, _ := producePrototypes(t, "TestCTagsRunnerSketchWithClassFunction.txt", "/home/megabug/Workspace/arduino-builder/src/arduino.cc/builder/test/sketch_class_function/sketch_class_function.ino")

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)
}

func TestCTagsRunnerSketchWithMultiFile(t *testing.T) {
prototypes, line := producePrototypes(t, "TestCTagsRunnerSketchWithMultifile.txt", "/tmp/apUNI8a/main.ino")

require.Equal(t, 0, line)
require.Equal(t, "void A7105_Setup();", prototypes[0].Prototype)
require.Equal(t, "void A7105_Reset();", prototypes[1].Prototype)
require.Equal(t, "int A7105_calibrate_VCB(uint8_t channel);", prototypes[2].Prototype)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BUG /tmp/test547238273/preproc/bug_callback.ino /^ public: BUG(void (*fn)(void)) {}$/;" kind:function line:6 class:BUG signature:(void (*fn)(void))
b /tmp/test547238273/preproc/bug_callback.ino /^BUG b(makeItBreak); \/\/this will break$/;" kind:prototype line:10 signature:(makeItBreak)returntype:BUG
setup /tmp/test547238273/preproc/bug_callback.ino /^void setup() {$/;" kind:function line:12 signature:() returntype:void
loop /tmp/test547238273/preproc/bug_callback.ino /^void loop() {}$/;" kind:function line:16 signature:() returntype:void
makeItBreak /tmp/test547238273/preproc/bug_callback.ino /^void makeItBreak() {}$/;" kind:function line:18 signature:() returntype:void
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
blub /tmp/test547238273/preproc/bug_callback.ino /^int blub(int a) {$/;" kind:function line:24 signature:(int a) returntype:int
Loading