Skip to content

Commit 90cd875

Browse files
committed
Fix #15100 (clang import: internalAstError "invalid AST location: <<built-in>" for simple hello.c)
1 parent 275f16a commit 90cd875

2 files changed

Lines changed: 66 additions & 14 deletions

File tree

‎lib/clangimport.cpp‎

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ static std::string unquote(const std::string &s)
123123
}
124124

125125

126+
// location in a buffer that is generated by clang: "<<built-in>:115:23, file.h:18:19>"
127+
static bool isGeneratedBufferLocation(const std::string &s, std::string::size_type pos = 0)
128+
{
129+
return s.compare(pos, 12, "<<built-in>:") == 0 || s.compare(pos, 17, "<<scratch space>:") == 0;
130+
}
131+
126132
static std::vector<std::string> splitString(const std::string &line)
127133
{
128134
std::vector<std::string> ret;
@@ -134,9 +140,11 @@ static std::vector<std::string> splitString(const std::string &line)
134140
pos1 = line.find_first_not_of(' ', pos1 + 1);
135141
continue;
136142
}
137-
if (line[pos1] == '<')
143+
if (line[pos1] == '<') {
138144
pos2 = line.find('>', pos1);
139-
else if (line[pos1] == '\"')
145+
if (pos2 != std::string::npos && isGeneratedBufferLocation(line, pos1))
146+
pos2 = line.find('>', pos2 + 1);
147+
} else if (line[pos1] == '\"')
140148
pos2 = line.find('\"', pos1+1);
141149
else if (line[pos1] == '\'') {
142150
pos2 = line.find('\'', pos1+1);
@@ -560,19 +568,32 @@ void clangimport::AstNode::setLocations(TokenList &tokenList, int file, int line
560568
if (pos != std::string::npos)
561569
col = strToInt<int>(ext.substr(pos+6, ext.find_first_of(":,>", pos+6) - (pos+6)));
562570
} else if (ext[0] == '<') {
563-
const std::string::size_type colon = ext.find(':');
564-
if (colon != std::string::npos) {
565-
const bool windowsPath = colon == 2 && ext.size() > 3 && ext[2] == ':';
566-
const std::string::size_type sep1 = windowsPath ? ext.find(':', 4) : colon;
567-
const std::string::size_type sep2 = ext.find(':', sep1 + 1);
568-
file = tokenList.appendFileIfNew(ext.substr(1, sep1 - 1));
569-
line = strToInt<int>(ext.substr(sep1 + 1, sep2 - sep1 - 1));
571+
// start of the file location
572+
std::string::size_type pos = 1;
573+
if (isGeneratedBufferLocation(ext)) {
574+
// Use the end of the range if that is a file location, otherwise the location is unchanged
575+
pos = ext.find(", ");
576+
if (pos != std::string::npos) {
577+
pos += 2;
578+
if (ext[pos] == '<' || ext.compare(pos, 4, "col:") == 0 || ext.compare(pos, 5, "line:") == 0)
579+
pos = std::string::npos;
580+
}
570581
}
571-
else {
572-
// "<invalid sloc>" are encountered in every AST dump by some built-in TypedefDecl
573-
// an completely empty location block was encountered with a CompoundStmt
574-
if (ext != "<<invalid sloc>" && ext != "<>")
575-
throw InternalError(nullptr, "invalid AST location: " + ext, InternalError::AST);
582+
if (pos != std::string::npos) {
583+
const std::string::size_type colon = ext.find(':', pos);
584+
if (colon != std::string::npos) {
585+
const bool windowsPath = colon == pos + 1 && ext.size() > pos + 2;
586+
const std::string::size_type sep1 = windowsPath ? ext.find(':', pos + 3) : colon;
587+
const std::string::size_type sep2 = ext.find(':', sep1 + 1);
588+
file = tokenList.appendFileIfNew(ext.substr(pos, sep1 - pos));
589+
line = strToInt<int>(ext.substr(sep1 + 1, sep2 - sep1 - 1));
590+
}
591+
else {
592+
// "<invalid sloc>" are encountered in every AST dump by some built-in TypedefDecl
593+
// an completely empty location block was encountered with a CompoundStmt
594+
if (ext != "<<invalid sloc>" && ext != "<>")
595+
throw InternalError(nullptr, "invalid AST location: " + ext, InternalError::AST);
596+
}
576597
}
577598
}
578599
}

‎test/testclangimport.cpp‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class TestClangImport : public TestFixture {
117117
TEST_CASE(vardecl6);
118118
TEST_CASE(vardecl7);
119119
TEST_CASE(vardeclInHeader);
120+
TEST_CASE(vardeclBuiltinLocation);
120121
TEST_CASE(whileStmt1);
121122
TEST_CASE(whileStmt2);
122123

@@ -1051,6 +1052,36 @@ class TestClangImport : public TestFixture {
10511052
parse(clang));
10521053
}
10531054

1055+
void vardeclBuiltinLocation() {
1056+
// #15100 - the location starts in a buffer that is generated by clang
1057+
const char clang[] = "|-VarDecl 0x32b8aa0 <1.c:1:1, col:5> col:5 a 'int'\n"
1058+
"|-VarDecl 0x32b8b78 <<built-in>:115:23, 1.h:18:19> col:19 b 'unsigned int'\n"
1059+
"|-VarDecl 0x32b8c50 <<scratch space>:2:1, col:5> col:5 c 'int'\n"
1060+
"`-VarDecl 0x32b8d28 <<scratch space>:41:1> col:5 d 'int'";
1061+
1062+
ASSERT_EQUALS("int a@1 ; unsigned int b@2 ; int c@3 ; int d@4 ;",
1063+
parse(clang));
1064+
1065+
const Settings settings = settingsBuilder().clang().build();
1066+
TokenList tokenlist{settings, Standards::Language::C};
1067+
Tokenizer tokenizer(std::move(tokenlist), *this);
1068+
std::istringstream istr(clang);
1069+
clangimport::parseClangAstDump(tokenizer, istr);
1070+
1071+
// the end of the range is used for "b", the location is unchanged for "c" and "d"
1072+
ASSERT_EQUALS(2, tokenizer.list.getFiles().size());
1073+
ASSERT_EQUALS("1.c", tokenizer.list.getFiles()[0]);
1074+
ASSERT_EQUALS("1.h", tokenizer.list.getFiles()[1]);
1075+
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "b");
1076+
ASSERT(tok);
1077+
ASSERT_EQUALS(1, tok->fileIndex());
1078+
ASSERT_EQUALS(18, tok->linenr());
1079+
tok = Token::findsimplematch(tokenizer.tokens(), "d");
1080+
ASSERT(tok);
1081+
ASSERT_EQUALS(1, tok->fileIndex());
1082+
ASSERT_EQUALS(18, tok->linenr());
1083+
}
1084+
10541085
void whileStmt1() {
10551086
const char clang[] = "`-FunctionDecl 0x3d45b18 <1.c:1:1, line:3:1> line:1:6 foo 'void ()'\n"
10561087
" `-CompoundStmt 0x3d45c48 <col:12, line:3:1>\n"

0 commit comments

Comments
 (0)