Skip to content

Commit

Permalink
Fix compiler crash in alternate name suggestion logic (issue ponylang…
Browse files Browse the repository at this point in the history
…#2508). (ponylang#2552)

* Fix for issue 2508

The pony_assert(ast_id(id == TK_ID) assumes that ast_id(id)) is
always a TK_ID, but that is not the true if the first child of case_ast
is a function or behavior.

This fix checks for a TK_ID for both first and second children of
case_ast and gives up if neither is a TK_ID instead of asserting.

* Add tests for suggest_alt_name

There are three cases tested plus a test for nothing can be suggested.
  • Loading branch information
winksaville authored and dipinhora committed Jun 5, 2018
1 parent 26623eb commit 41c74b9
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 6 deletions.
28 changes: 22 additions & 6 deletions src/libponyc/pass/refer.c
Expand Up @@ -222,14 +222,30 @@ static const char* suggest_alt_name(ast_t* ast, const char* name)
{
ast_t* id = case_ast;

if(ast_id(id) != TK_ID)
id = ast_child(id);
int tk = ast_id(id);
if(tk != TK_ID)
{
AST_GET_CHILDREN(case_ast, first, second);

pony_assert(ast_id(id) == TK_ID);
const char* try_name = ast_name(id);
if((tk = ast_id(first)) == TK_ID)
{
// First is a TK_ID give it as a suggestion
id = first;
} else if((tk = ast_id(second)) == TK_ID) {
// Second is a TK_ID give it as a suggestion
id = second;
} else {
// Giving up on different case as tk != TK_ID
}
}

if(ast_get(ast, try_name, NULL) != NULL)
return try_name;
if(tk == TK_ID)
{
const char* try_name = ast_name(id);

if(ast_get(ast, try_name, NULL) != NULL)
return try_name;
}
}

// Give up
Expand Down
68 changes: 68 additions & 0 deletions test/libponyc/suggest_alt_name.cc
@@ -0,0 +1,68 @@
#include <gtest/gtest.h>
#include <platform.h>

#include "util.h"

#define TEST_ERRORS(src, err1) \
{ const char* errs[] = {err1, NULL}; \
DO(test_expected_errors(src, "ir", errs)); }

class SuggestAltNameTest : public PassTest
{};

TEST_F(SuggestAltNameTest, SuggestAltName_Private)
{
const char* src =
"actor Main\n"
" var _aStr: String = \"help\"\n"

" new create(env: Env) =>\n"
" _aStr = xx()\n"

" fun xx(): String =>\n"
" aStr // Undefined suggest _aStr\n";

TEST_ERRORS(src,
"can't find declaration of 'aStr', did you mean '_aStr'?");
}

TEST_F(SuggestAltNameTest, SuggestAltName_DifferentCaseVariable)
{
const char* src =
"actor Main\n"
" var aStr: String = \"help\"\n"

" new create(env: Env) =>\n"
" aStr = xx()\n"

" fun xx(): String =>\n"
" astr // Undefined, suggest aStr\n";

TEST_ERRORS(src,
"can't find declaration of 'astr', did you mean 'aStr'?");
}

TEST_F(SuggestAltNameTest, SuggestAltName_DifferentCaseMethod)
{
const char* src =
"actor Main\n"
" new create(env: Env) =>\n"
" doit() // Undefined, suggest doIt\n"

" fun doIt() =>\n"
" None\n";

TEST_ERRORS(src,
"can't find declaration of 'doit', did you mean 'doIt'?");
}

TEST_F(SuggestAltNameTest, SuggestAltName_NothingToSuggest)
{
const char* src =
"actor Main\n"
" new create(env: Env) =>\n"
" doIt() // Undefined, nothing to suggest\n";

TEST_ERRORS(src,
"can't find declaration of 'doIt'");
}

0 comments on commit 41c74b9

Please sign in to comment.