From a95ff5d3945c0bb8afcd5d2dec51f0987b5c2f84 Mon Sep 17 00:00:00 2001 From: kamphaus Date: Thu, 26 Apr 2018 02:23:36 +0200 Subject: [PATCH] Try parsing for all lines of muli-line character literal. Fixes #675 (#676) --- ast/character_literal.go | 66 +++++++++++++++++++++-------------- ast/character_literal_test.go | 39 +++++++++++++++++++++ tests/cast.c | 24 ++++++++++++- 3 files changed, 101 insertions(+), 28 deletions(-) diff --git a/ast/character_literal.go b/ast/character_literal.go index 0b7e5cf8a..04d6930ca 100644 --- a/ast/character_literal.go +++ b/ast/character_literal.go @@ -81,45 +81,57 @@ func RepairCharacterLiteralsFromSource(rootNode Node, preprocessedFile string) [ for _, node := range characterLiteralNodes { cNode := node.(*CharacterLiteral) - - // Use the node position to retrieve the original line from the - // preprocessed source. pos := node.Position() - line, err := - cc.GetLineFromPreprocessedFile(preprocessedFile, pos.File, pos.Line) - - // If there was a problem reading the line we should raise a warning and - // use the value we have. Hopefully that will be an accurate enough - // representation. + var ( + err error + lastLine = pos.LineEnd + i int + ) + if lastLine == 0 { + lastLine = pos.Line + } + for line := pos.Line; line <= lastLine; line++ { + i, err = parseCharacterLiteralFromPosition(preprocessedFile, pos, line) + if err == nil { + cNode.Value = i + break + } + } if err != nil { errs = append(errs, CharacterLiteralError{ Node: cNode, Err: err, }) } - - // Extract the exact value from the line. - if pos.Column-1 >= len(line) { - errs = append(errs, CharacterLiteralError{ - Node: cNode, - Err: errors.New("cannot get exact value"), - }) - } else { - literal := line[pos.Column-1:] - if i, err := parseCharacterLiteralFromSource(literal); err == nil { - cNode.Value = i - } else { - errs = append(errs, CharacterLiteralError{ - Node: cNode, - Err: fmt.Errorf("cannot parse character literal: %v from %s", err, literal), - }) - } - } } return errs } +func parseCharacterLiteralFromPosition(preprocessedFile string, pos Position, lineNbr int) (ret int, err error) { + // Use the node position to retrieve the original line from the + // preprocessed source. + line, err := + cc.GetLineFromPreprocessedFile(preprocessedFile, pos.File, lineNbr) + + // If there was a problem reading the line we should raise a warning and + // use the value we have. Hopefully that will be an accurate enough + // representation. + if err != nil { + return 0, err + } + + // Extract the exact value from the line. + if pos.Column-1 >= len(line) { + return 0, errors.New("cannot get exact value") + } + literal := line[pos.Column-1:] + if ret, err = parseCharacterLiteralFromSource(literal); err == nil { + return ret, nil + } + return 0, fmt.Errorf("cannot parse character literal: %v from %s", err, literal) +} + func parseCharacterLiteralFromSource(literal string) (ret int, err error) { runes := []rune(literal) if len(runes) < 1 { diff --git a/ast/character_literal_test.go b/ast/character_literal_test.go index ba7bdbfac..2528ba9d1 100644 --- a/ast/character_literal_test.go +++ b/ast/character_literal_test.go @@ -361,3 +361,42 @@ func prepareRepairFromSourceTest(t *testing.T, fileContent string, test func(fil test(ppFilePath) } + +func TestCharacterLiteralRepairFromSourceMultiline(t *testing.T) { + cl := &CharacterLiteral{ + Addr: 0x7f980b858308, + Pos: NewPositionFromString("col:12"), + Type: "int", + Value: 10, + ChildNodes: []Node{}, + } + cl.Pos.LineEnd = 6 + root := &CompoundStmt{ + Pos: Position{File: "dummy.c", Line: 5}, + ChildNodes: []Node{cl}, + } + FixPositions([]Node{root}) + type test struct { + file string + expected int + err error + } + tests := []test{ + {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = '\nxxxxxxxxx, };\nyyyy", 10, fmt.Errorf("cannot parse character literal: illegal character '}' at index 0 from };")}, + {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = 'A'zzz\nyyyy", int('A'), nil}, + {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = {\nxxxxxxxxx, 'B'};\nyyyy", int('B'), nil}, + } + for _, test := range tests { + prepareRepairFromSourceTest(t, test.file, func(ppFilePath string) { + errors := RepairCharacterLiteralsFromSource(root, ppFilePath) + if cl.Value != test.expected { + t.Errorf("RepairCharacterLiteralsFromSource - expected: %x, got: %x", test.expected, cl.Value) + } + if test.err != nil && len(errors) == 0 || test.err == nil && len(errors) != 0 { + t.Errorf("RepairCharacterLiteralsFromSource - error should match: expected: %v, got: %v", test.err, errors) + } else if test.err != nil && errors[0].Err.Error() != test.err.Error() { + t.Errorf("RepairCharacterLiteralsFromSource - error should match: expected: %s, got: %s", test.err.Error(), errors[0].Err.Error()) + } + }) + } +} diff --git a/tests/cast.c b/tests/cast.c index 83aa6e41b..02ae14fa1 100644 --- a/tests/cast.c +++ b/tests/cast.c @@ -93,14 +93,33 @@ void test_preprocessor() } typedef unsigned char pcre_uchar; + void caststr() { pcre_uchar str[] = "abcd"; is_streq((char *) str, "abcd"); } +static const pcre_uchar TEST[] = { + 'x', (pcre_uchar) CHAR_NBSP, '\n', '\0' }; + +#define CHAR_E ((unsigned char) 'e') +static const pcre_uchar TEST2[] = { + 'x', (pcre_uchar) CHAR_NBSP, '\n', + (pcre_uchar) CHAR_E, '\0' }; + + +void test_static_array() +{ + is_eq('x', TEST[0]); + is_eq((pcre_uchar) '\xa0', TEST[1]); + is_eq('\n', TEST[2]); + is_eq('x', TEST2[0]); + is_eq('e', TEST2[3]); // can distinguish character at same column in different lines +} + int main() { - plan(31); + plan(36); START_TEST(cast); START_TEST(castbool); @@ -194,5 +213,8 @@ int main() diag("Typedef slice convertion") caststr(); + diag("Compare with static array") + test_static_array(); + done_testing(); }