Skip to content

Commit 2e770ed

Browse files
[libclang] Compute the right spelling location (#72400)
Locations inside macro expansions have different spelling/expansion locations. Apply a FIXME to make the libclang function clang_getSpellingLocation return the right spelling location, and adapt the testsuite driver code to use the file location rather than the spelling location to compute source ranges. Co-authored-by: Matthieu Eyraud <[email protected]>
1 parent b8f3024 commit 2e770ed

File tree

4 files changed

+61
-30
lines changed

4 files changed

+61
-30
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,9 @@ clang-format
710710
libclang
711711
--------
712712

713+
- ``clang_getSpellingLocation`` now correctly resolves macro expansions; that
714+
is, it returns the spelling location instead of the expansion location.
715+
713716
Static Analyzer
714717
---------------
715718

clang/tools/c-index-test/c-index-test.c

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -464,10 +464,10 @@ static void PrintRange(CXSourceRange R, const char *str) {
464464
CXFile begin_file, end_file;
465465
unsigned begin_line, begin_column, end_line, end_column;
466466

467-
clang_getSpellingLocation(clang_getRangeStart(R),
468-
&begin_file, &begin_line, &begin_column, 0);
469-
clang_getSpellingLocation(clang_getRangeEnd(R),
470-
&end_file, &end_line, &end_column, 0);
467+
clang_getFileLocation(clang_getRangeStart(R), &begin_file, &begin_line,
468+
&begin_column, 0);
469+
clang_getFileLocation(clang_getRangeEnd(R), &end_file, &end_line, &end_column,
470+
0);
471471
if (!begin_file || !end_file)
472472
return;
473473

@@ -849,13 +849,13 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
849849
printf(", ");
850850

851851
Loc = clang_getCursorLocation(Ovl);
852-
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
852+
clang_getFileLocation(Loc, 0, &line, &column, 0);
853853
printf("%d:%d", line, column);
854854
}
855855
printf("]");
856856
} else {
857857
CXSourceLocation Loc = clang_getCursorLocation(Referenced);
858-
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
858+
clang_getFileLocation(Loc, 0, &line, &column, 0);
859859
printf(":%d:%d", line, column);
860860
}
861861

@@ -1047,7 +1047,7 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
10471047
if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
10481048
CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
10491049
CXString Name = clang_getCursorSpelling(SpecializationOf);
1050-
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
1050+
clang_getFileLocation(Loc, 0, &line, &column, 0);
10511051
printf(" [Specialization of %s:%d:%d]",
10521052
clang_getCString(Name), line, column);
10531053
clang_disposeString(Name);
@@ -1094,7 +1094,7 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
10941094
printf(" [Overrides ");
10951095
for (I = 0; I != num_overridden; ++I) {
10961096
CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
1097-
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
1097+
clang_getFileLocation(Loc, 0, &line, &column, 0);
10981098
lineCols[I].line = line;
10991099
lineCols[I].col = column;
11001100
}
@@ -1257,8 +1257,8 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) {
12571257
fprintf(stderr, "%s\n", clang_getCString(Msg));
12581258
clang_disposeString(Msg);
12591259

1260-
clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
1261-
&file, 0, 0, 0);
1260+
clang_getFileLocation(clang_getDiagnosticLocation(Diagnostic), &file, 0, 0,
1261+
0);
12621262
if (!file)
12631263
return;
12641264

@@ -1271,9 +1271,8 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) {
12711271
CXSourceLocation end = clang_getRangeEnd(range);
12721272
unsigned start_line, start_column, end_line, end_column;
12731273
CXFile start_file, end_file;
1274-
clang_getSpellingLocation(start, &start_file, &start_line,
1275-
&start_column, 0);
1276-
clang_getSpellingLocation(end, &end_file, &end_line, &end_column, 0);
1274+
clang_getFileLocation(start, &start_file, &start_line, &start_column, 0);
1275+
clang_getFileLocation(end, &end_file, &end_line, &end_column, 0);
12771276
if (clang_equalLocations(start, end)) {
12781277
/* Insertion. */
12791278
if (start_file == file)
@@ -1356,7 +1355,7 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
13561355
if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
13571356
CXSourceLocation Loc = clang_getCursorLocation(Cursor);
13581357
unsigned line, column;
1359-
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
1358+
clang_getFileLocation(Loc, 0, &line, &column, 0);
13601359
printf("// %s: %s:%d:%d: ", FileCheckPrefix,
13611360
GetCursorSource(Cursor), line, column);
13621361
PrintCursor(Cursor, Data->CommentSchemaFile);
@@ -1417,7 +1416,7 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
14171416
curColumn++;
14181417

14191418
Loc = clang_getCursorLocation(Cursor);
1420-
clang_getSpellingLocation(Loc, &file, 0, 0, 0);
1419+
clang_getFileLocation(Loc, &file, 0, 0, 0);
14211420

14221421
source = clang_getFileName(file);
14231422
if (clang_getCString(source)) {
@@ -1483,8 +1482,7 @@ void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
14831482
for (i = 0; i < includeStackLen; ++i) {
14841483
CXFile includingFile;
14851484
unsigned line, column;
1486-
clang_getSpellingLocation(includeStack[i], &includingFile, &line,
1487-
&column, 0);
1485+
clang_getFileLocation(includeStack[i], &includingFile, &line, &column, 0);
14881486
fname = clang_getFileName(includingFile);
14891487
printf(" %s:%d:%d\n", clang_getCString(fname), line, column);
14901488
clang_disposeString(fname);
@@ -2984,7 +2982,7 @@ static void inspect_print_cursor(CXCursor Cursor) {
29842982
CXString Spelling;
29852983
const char *cspell;
29862984
unsigned line, column;
2987-
clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
2985+
clang_getFileLocation(CursorLoc, 0, &line, &column, 0);
29882986
printf("%d:%d ", line, column);
29892987
PrintCursor(Cursor, NULL);
29902988
PrintCursorExtent(Cursor);
@@ -3100,7 +3098,7 @@ static void inspect_evaluate_cursor(CXCursor Cursor) {
31003098
unsigned line, column;
31013099
CXEvalResult ER;
31023100

3103-
clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
3101+
clang_getFileLocation(CursorLoc, 0, &line, &column, 0);
31043102
printf("%d:%d ", line, column);
31053103
PrintCursor(Cursor, NULL);
31063104
PrintCursorExtent(Cursor);
@@ -3135,7 +3133,7 @@ static void inspect_macroinfo_cursor(CXCursor Cursor) {
31353133
CXString Spelling;
31363134
const char *cspell;
31373135
unsigned line, column;
3138-
clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
3136+
clang_getFileLocation(CursorLoc, 0, &line, &column, 0);
31393137
printf("%d:%d ", line, column);
31403138
PrintCursor(Cursor, NULL);
31413139
PrintCursorExtent(Cursor);
@@ -4328,10 +4326,10 @@ int perform_token_annotation(int argc, const char **argv) {
43284326
skipped_ranges = clang_getSkippedRanges(TU, file);
43294327
for (i = 0; i != skipped_ranges->count; ++i) {
43304328
unsigned start_line, start_column, end_line, end_column;
4331-
clang_getSpellingLocation(clang_getRangeStart(skipped_ranges->ranges[i]),
4332-
0, &start_line, &start_column, 0);
4333-
clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges->ranges[i]),
4334-
0, &end_line, &end_column, 0);
4329+
clang_getFileLocation(clang_getRangeStart(skipped_ranges->ranges[i]), 0,
4330+
&start_line, &start_column, 0);
4331+
clang_getFileLocation(clang_getRangeEnd(skipped_ranges->ranges[i]), 0,
4332+
&end_line, &end_column, 0);
43354333
printf("Skipping: ");
43364334
PrintExtent(stdout, start_line, start_column, end_line, end_column);
43374335
printf("\n");
@@ -4351,10 +4349,10 @@ int perform_token_annotation(int argc, const char **argv) {
43514349
case CXToken_Literal: kind = "Literal"; break;
43524350
case CXToken_Comment: kind = "Comment"; break;
43534351
}
4354-
clang_getSpellingLocation(clang_getRangeStart(extent),
4355-
0, &start_line, &start_column, 0);
4356-
clang_getSpellingLocation(clang_getRangeEnd(extent),
4357-
0, &end_line, &end_column, 0);
4352+
clang_getFileLocation(clang_getRangeStart(extent), 0, &start_line,
4353+
&start_column, 0);
4354+
clang_getFileLocation(clang_getRangeEnd(extent), 0, &end_line, &end_column,
4355+
0);
43584356
printf("%s: \"%s\" ", kind, clang_getCString(spelling));
43594357
clang_disposeString(spelling);
43604358
PrintExtent(stdout, start_line, start_column, end_line, end_column);

clang/tools/libclang/CXSourceLocation.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,7 @@ void clang_getSpellingLocation(CXSourceLocation location,
319319

320320
const SourceManager &SM =
321321
*static_cast<const SourceManager*>(location.ptr_data[0]);
322-
// FIXME: This should call SourceManager::getSpellingLoc().
323-
SourceLocation SpellLoc = SM.getFileLoc(Loc);
322+
SourceLocation SpellLoc = SM.getSpellingLoc(Loc);
324323
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
325324
FileID FID = LocInfo.first;
326325
unsigned FileOffset = LocInfo.second;

clang/unittests/libclang/LibclangTest.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,37 @@ void func() {}
12921292
EXPECT_EQ(attrCount, 1);
12931293
}
12941294

1295+
TEST_F(LibclangParseTest, clang_getSpellingLocation) {
1296+
std::string fileName = "main.c";
1297+
WriteFile(fileName, "#define X(value) int x = value;\nX(42)\n");
1298+
1299+
ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), nullptr, 0,
1300+
nullptr, 0, TUFlags);
1301+
1302+
int declarationCount = 0;
1303+
Traverse([&declarationCount](CXCursor cursor,
1304+
CXCursor parent) -> CXChildVisitResult {
1305+
if (cursor.kind == CXCursor_VarDecl) {
1306+
declarationCount++;
1307+
1308+
CXSourceLocation cxl = clang_getCursorLocation(cursor);
1309+
unsigned line;
1310+
1311+
// We expect clang_getFileLocation to return the expansion location,
1312+
// whereas clang_getSpellingLocation should resolve the macro expansion
1313+
// and return the location of the macro definition.
1314+
clang_getFileLocation(cxl, nullptr, &line, nullptr, nullptr);
1315+
EXPECT_EQ(line, 2U);
1316+
clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
1317+
EXPECT_EQ(line, 1U);
1318+
}
1319+
1320+
return CXChildVisit_Recurse;
1321+
});
1322+
1323+
EXPECT_EQ(declarationCount, 1);
1324+
}
1325+
12951326
class LibclangRewriteTest : public LibclangParseTest {
12961327
public:
12971328
CXRewriter Rew = nullptr;

0 commit comments

Comments
 (0)