Improve the implementation of libclang's token-annotation logic for

entities in the preprocessing record. Previously, we would only end up
getting the first token of a preprocessing record annotated
correctly. For example, given

  #include "foo.h"

we would only get the '#' annotated as an inclusion directive; the
'include' and '"foo.h"' tokens would be given the general 'processing
directive' annotation.

Now, we get proper annotations for entities in the preprocessing
record.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117001 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-10-21 06:10:04 +00:00
Родитель 13f8cbfbd2
Коммит 4419b67557
4 изменённых файлов: 120 добавлений и 66 удалений

Просмотреть файл

@ -2,6 +2,6 @@
// RUN: c-index-test -test-annotate-tokens=%s:1:1:2:1 %s | FileCheck %s
// CHECK: Punctuation: "#" [1:1 - 1:2] inclusion directive=annotate-tokens-include.h
// CHECK: Identifier: "include" [1:2 - 1:9] preprocessing directive=
// CHECK: Literal: ""annotate-tokens-include.h"" [1:10 - 1:37] preprocessing directive=
// CHECK: Identifier: "include" [1:2 - 1:9] inclusion directive=annotate-tokens-include.h
// CHECK: Literal: ""annotate-tokens-include.h"" [1:10 - 1:37] inclusion directive=annotate-tokens-include.h

Просмотреть файл

@ -29,27 +29,27 @@ void test() {
// CHECK: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
// CHECK: Identifier: "define" [2:2 - 2:8] preprocessing directive=
// CHECK: Identifier: "STILL_NOTHING" [2:9 - 2:22] macro definition=STILL_NOTHING
// CHECK: Identifier: "NOTHING" [2:23 - 2:30] preprocessing directive=
// CHECK: Punctuation: "(" [2:30 - 2:31] preprocessing directive=
// CHECK: Identifier: "honk" [2:31 - 2:35] preprocessing directive=
// CHECK: Punctuation: "," [2:35 - 2:36] preprocessing directive=
// CHECK: Identifier: "warble" [2:36 - 2:42] preprocessing directive=
// CHECK: Punctuation: ")" [2:42 - 2:43] preprocessing directive=
// CHECK: Identifier: "NOTHING" [2:23 - 2:30] macro definition=STILL_NOTHING
// CHECK: Punctuation: "(" [2:30 - 2:31] macro definition=STILL_NOTHING
// CHECK: Identifier: "honk" [2:31 - 2:35] macro definition=STILL_NOTHING
// CHECK: Punctuation: "," [2:35 - 2:36] macro definition=STILL_NOTHING
// CHECK: Identifier: "warble" [2:36 - 2:42] macro definition=STILL_NOTHING
// CHECK: Punctuation: ")" [2:42 - 2:43] macro definition=STILL_NOTHING
// CHECK: Punctuation: "#" [3:1 - 3:2] preprocessing directive=
// CHECK: Identifier: "define" [3:2 - 3:8] preprocessing directive=
// CHECK: Identifier: "BAR" [3:9 - 3:12] macro definition=BAR
// CHECK: Identifier: "baz" [3:13 - 3:16] preprocessing directive=
// CHECK: Identifier: "baz" [3:13 - 3:16] macro definition=BAR
// CHECK: Punctuation: "#" [4:1 - 4:2] preprocessing directive=
// CHECK: Identifier: "define" [4:2 - 4:8] preprocessing directive=
// CHECK: Identifier: "WIBBLE" [4:9 - 4:15] macro definition=WIBBLE
// CHECK: Punctuation: "(" [4:15 - 4:16] preprocessing directive=
// CHECK: Identifier: "X" [4:16 - 4:17] preprocessing directive=
// CHECK: Punctuation: "," [4:17 - 4:18] preprocessing directive=
// CHECK: Identifier: "Y" [4:19 - 4:20] preprocessing directive=
// CHECK: Punctuation: ")" [4:20 - 4:21] preprocessing directive=
// CHECK: Identifier: "X" [4:22 - 4:23] preprocessing directive=
// CHECK: Punctuation: "##" [4:23 - 4:25] preprocessing directive=
// CHECK: Identifier: "Y" [4:25 - 4:26] preprocessing directive=
// CHECK: Punctuation: "(" [4:15 - 4:16] macro definition=WIBBLE
// CHECK: Identifier: "X" [4:16 - 4:17] macro definition=WIBBLE
// CHECK: Punctuation: "," [4:17 - 4:18] macro definition=WIBBLE
// CHECK: Identifier: "Y" [4:19 - 4:20] macro definition=WIBBLE
// CHECK: Punctuation: ")" [4:20 - 4:21] macro definition=WIBBLE
// CHECK: Identifier: "X" [4:22 - 4:23] macro definition=WIBBLE
// CHECK: Punctuation: "##" [4:23 - 4:25] macro definition=WIBBLE
// CHECK: Identifier: "Y" [4:25 - 4:26] macro definition=WIBBLE
// CHECK: Identifier: "NOTHING" [5:1 - 5:8] macro instantiation=NOTHING:1:9
// CHECK: Punctuation: "(" [5:8 - 5:9]
// CHECK: Identifier: "more" [5:9 - 5:13]
@ -69,31 +69,31 @@ void test() {
// CHECK: Identifier: "STILL_NOTHING" [6:9 - 6:22] macro instantiation=STILL_NOTHING:2:9
// CHECK: Punctuation: ";" [6:22 - 6:23]
// CHECK: Punctuation: "#" [7:1 - 7:2] inclusion directive=foo.h
// CHECK: Identifier: "include" [7:2 - 7:9] preprocessing directive=
// CHECK: Literal: ""foo.h"" [7:10 - 7:17] preprocessing directive=
// CHECK: Identifier: "include" [7:2 - 7:9] inclusion directive=foo.h
// CHECK: Literal: ""foo.h"" [7:10 - 7:17] inclusion directive=foo.h
// CHECK: Punctuation: "#" [8:1 - 8:2] preprocessing directive=
// CHECK: Identifier: "undef" [8:2 - 8:7] preprocessing directive=
// CHECK: Identifier: "BAR" [8:8 - 8:11] preprocessing directive=
// CHECK: Punctuation: "#" [10:1 - 10:2] preprocessing directive=
// CHECK: Identifier: "define" [10:2 - 10:8] preprocessing directive=
// CHECK: Identifier: "REVERSE_MACRO" [10:9 - 10:22] macro definition=REVERSE_MACRO
// CHECK: Punctuation: "(" [10:22 - 10:23] preprocessing directive=
// CHECK: Identifier: "x" [10:23 - 10:24] preprocessing directive=
// CHECK: Punctuation: "," [10:24 - 10:25] preprocessing directive=
// CHECK: Identifier: "y" [10:25 - 10:26] preprocessing directive=
// CHECK: Punctuation: ")" [10:26 - 10:27] preprocessing directive=
// CHECK: Identifier: "y" [10:28 - 10:29] preprocessing directive=
// CHECK: Punctuation: "+" [10:30 - 10:31] preprocessing directive=
// CHECK: Identifier: "x" [10:32 - 10:33] preprocessing directive=
// CHECK: Punctuation: "(" [10:22 - 10:23] macro definition=REVERSE_MACRO
// CHECK: Identifier: "x" [10:23 - 10:24] macro definition=REVERSE_MACRO
// CHECK: Punctuation: "," [10:24 - 10:25] macro definition=REVERSE_MACRO
// CHECK: Identifier: "y" [10:25 - 10:26] macro definition=REVERSE_MACRO
// CHECK: Punctuation: ")" [10:26 - 10:27] macro definition=REVERSE_MACRO
// CHECK: Identifier: "y" [10:28 - 10:29] macro definition=REVERSE_MACRO
// CHECK: Punctuation: "+" [10:30 - 10:31] macro definition=REVERSE_MACRO
// CHECK: Identifier: "x" [10:32 - 10:33] macro definition=REVERSE_MACRO
// CHECK: Punctuation: "#" [11:1 - 11:2] preprocessing directive=
// CHECK: Identifier: "define" [11:2 - 11:8] preprocessing directive=
// CHECK: Identifier: "TWICE_MACRO" [11:9 - 11:20] macro definition=TWICE_MACRO
// CHECK: Punctuation: "(" [11:20 - 11:21] preprocessing directive=
// CHECK: Identifier: "y" [11:21 - 11:22] preprocessing directive=
// CHECK: Punctuation: ")" [11:22 - 11:23] preprocessing directive=
// CHECK: Identifier: "y" [11:24 - 11:25] preprocessing directive=
// CHECK: Punctuation: "+" [11:26 - 11:27] preprocessing directive=
// CHECK: Identifier: "y" [11:28 - 11:29] preprocessing directive=
// CHECK: Punctuation: "(" [11:20 - 11:21] macro definition=TWICE_MACRO
// CHECK: Identifier: "y" [11:21 - 11:22] macro definition=TWICE_MACRO
// CHECK: Punctuation: ")" [11:22 - 11:23] macro definition=TWICE_MACRO
// CHECK: Identifier: "y" [11:24 - 11:25] macro definition=TWICE_MACRO
// CHECK: Punctuation: "+" [11:26 - 11:27] macro definition=TWICE_MACRO
// CHECK: Identifier: "y" [11:28 - 11:29] macro definition=TWICE_MACRO
// CHECK: Keyword: "void" [13:1 - 13:5] FunctionDecl=test_macro_args:13:6 (Definition)
// CHECK: Identifier: "test_macro_args" [13:6 - 13:21] FunctionDecl=test_macro_args:13:6 (Definition)
// CHECK: Punctuation: "(" [13:21 - 13:22] FunctionDecl=test_macro_args:13:6 (Definition)
@ -140,23 +140,23 @@ void test() {
// CHECK: Punctuation: "#" [21:1 - 21:2] preprocessing directive=
// CHECK: Identifier: "define" [21:2 - 21:8] preprocessing directive=
// CHECK: Identifier: "fun_with_macro_bodies" [21:9 - 21:30] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: "(" [21:30 - 21:31] preprocessing directive=
// CHECK: Identifier: "x" [21:31 - 21:32] preprocessing directive=
// CHECK: Punctuation: "," [21:32 - 21:33] preprocessing directive=
// CHECK: Identifier: "y" [21:34 - 21:35] preprocessing directive=
// CHECK: Punctuation: ")" [21:35 - 21:36] preprocessing directive=
// CHECK: Keyword: "do" [21:37 - 21:39] preprocessing directive=
// CHECK: Punctuation: "{" [21:40 - 21:41] preprocessing directive=
// CHECK: Keyword: "if" [21:42 - 21:44] preprocessing directive=
// CHECK: Punctuation: "(" [21:45 - 21:46] preprocessing directive=
// CHECK: Identifier: "x" [21:46 - 21:47] preprocessing directive=
// CHECK: Punctuation: ")" [21:47 - 21:48] preprocessing directive=
// CHECK: Identifier: "y" [21:49 - 21:50] preprocessing directive=
// CHECK: Punctuation: "}" [21:51 - 21:52] preprocessing directive=
// CHECK: Keyword: "while" [21:53 - 21:58] preprocessing directive=
// CHECK: Punctuation: "(" [21:59 - 21:60] preprocessing directive=
// CHECK: Literal: "0" [21:60 - 21:61] preprocessing directive=
// CHECK: Punctuation: ")" [21:61 - 21:62] preprocessing directive=
// CHECK: Punctuation: "(" [21:30 - 21:31] macro definition=fun_with_macro_bodies
// CHECK: Identifier: "x" [21:31 - 21:32] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: "," [21:32 - 21:33] macro definition=fun_with_macro_bodies
// CHECK: Identifier: "y" [21:34 - 21:35] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: ")" [21:35 - 21:36] macro definition=fun_with_macro_bodies
// CHECK: Keyword: "do" [21:37 - 21:39] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: "{" [21:40 - 21:41] macro definition=fun_with_macro_bodies
// CHECK: Keyword: "if" [21:42 - 21:44] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: "(" [21:45 - 21:46] macro definition=fun_with_macro_bodies
// CHECK: Identifier: "x" [21:46 - 21:47] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: ")" [21:47 - 21:48] macro definition=fun_with_macro_bodies
// CHECK: Identifier: "y" [21:49 - 21:50] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: "}" [21:51 - 21:52] macro definition=fun_with_macro_bodies
// CHECK: Keyword: "while" [21:53 - 21:58] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: "(" [21:59 - 21:60] macro definition=fun_with_macro_bodies
// CHECK: Literal: "0" [21:60 - 21:61] macro definition=fun_with_macro_bodies
// CHECK: Punctuation: ")" [21:61 - 21:62] macro definition=fun_with_macro_bodies
// CHECK: Keyword: "void" [23:1 - 23:5] FunctionDecl=test:23:6 (Definition)
// CHECK: Identifier: "test" [23:6 - 23:10] FunctionDecl=test:23:6 (Definition)
// CHECK: Punctuation: "(" [23:10 - 23:11] FunctionDecl=test:23:6 (Definition)

Просмотреть файл

@ -285,7 +285,7 @@ void f() {
// CHECK: Punctuation: "#" [63:1 - 63:2] preprocessing directive=
// CHECK: Identifier: "define" [63:2 - 63:8] preprocessing directive=
// CHECK: Identifier: "VAL" [63:9 - 63:12] macro definition=VAL
// CHECK: Literal: "0" [63:13 - 63:14] preprocessing directive=
// CHECK: Literal: "0" [63:13 - 63:14] macro definition=VAL
// CHECK: Punctuation: "@" [65:1 - 65:2] ObjCInterfaceDecl=R7974151:65:12
// CHECK: Keyword: "interface" [65:2 - 65:11] ObjCInterfaceDecl=R7974151:65:12
// CHECK: Identifier: "R7974151" [65:12 - 65:20] ObjCInterfaceDecl=R7974151:65:12

Просмотреть файл

@ -3657,6 +3657,7 @@ class AnnotateTokensWorker {
CXCursor *Cursors;
unsigned NumTokens;
unsigned TokIdx;
unsigned PreprocessingTokIdx;
CursorVisitor AnnotateVis;
SourceManager &SrcMgr;
@ -3672,7 +3673,7 @@ public:
CXToken *tokens, CXCursor *cursors, unsigned numTokens,
ASTUnit *CXXUnit, SourceRange RegionOfInterest)
: Annotated(annotated), Tokens(tokens), Cursors(cursors),
NumTokens(numTokens), TokIdx(0),
NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
AnnotateVis(CXXUnit, AnnotateTokensVisitor, this,
Decl::MaxPCHLevel, RegionOfInterest),
SrcMgr(CXXUnit->getSourceManager()) {}
@ -3690,7 +3691,9 @@ void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
for (unsigned I = 0 ; I < TokIdx ; ++I) {
AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
if (Pos != Annotated.end())
if (Pos != Annotated.end() &&
(clang_isInvalid(Cursors[I].kind) ||
Pos->second.kind != CXCursor_PreprocessingDirective))
Cursors[I] = Pos->second;
}
@ -3706,16 +3709,66 @@ void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
}
enum CXChildVisitResult
AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
CXSourceLocation Loc = clang_getCursorLocation(cursor);
// We can always annotate a preprocessing directive/macro instantiation.
if (clang_isPreprocessing(cursor.kind)) {
Annotated[Loc.int_data] = cursor;
SourceRange cursorRange = getRawCursorExtent(cursor);
if (clang_isPreprocessing(cursor.kind)) {
// For macro instantiations, just note where the beginning of the macro
// instantiation occurs.
if (cursor.kind == CXCursor_MacroInstantiation) {
Annotated[Loc.int_data] = cursor;
return CXChildVisit_Recurse;
}
if (cursorRange.isInvalid())
return CXChildVisit_Continue;
// Items in the preprocessing record are kept separate from items in
// declarations, so we keep a separate token index.
unsigned SavedTokIdx = TokIdx;
TokIdx = PreprocessingTokIdx;
// Skip tokens up until we catch up to the beginning of the preprocessing
// entry.
while (MoreTokens()) {
const unsigned I = NextToken();
SourceLocation TokLoc = GetTokenLoc(I);
switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
case RangeBefore:
AdvanceToken();
continue;
case RangeAfter:
case RangeOverlap:
break;
}
break;
}
// Look at all of the tokens within this range.
while (MoreTokens()) {
const unsigned I = NextToken();
SourceLocation TokLoc = GetTokenLoc(I);
switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) {
case RangeBefore:
assert(0 && "Infeasible");
case RangeAfter:
break;
case RangeOverlap:
Cursors[I] = cursor;
AdvanceToken();
continue;
}
break;
}
// Save the preprocessing token index; restore the non-preprocessing
// token index.
PreprocessingTokIdx = TokIdx;
TokIdx = SavedTokIdx;
return CXChildVisit_Recurse;
}
SourceRange cursorRange = getRawCursorExtent(cursor);
if (cursorRange.isInvalid())
return CXChildVisit_Continue;
@ -3753,7 +3806,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
// directive. Here we assume that the default construction of CXCursor
// results in CXCursor.kind being an initialized value (i.e., 0). If
// this isn't the case, we can fix by doing lookup + insertion.
CXCursor &oldC = Annotated[rawEncoding];
if (!clang_isPreprocessing(oldC.kind))
oldC = cursor;
@ -3815,6 +3868,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
for (unsigned I = BeforeChildren; I != AfterChildren; ++I) {
if (!clang_isInvalid(clang_getCursorKind(Cursors[I])))
break;
Cursors[I] = cursor;
}
// Scan the tokens that are at the end of the cursor, but are not captured
@ -3841,14 +3895,14 @@ void clang_annotateTokens(CXTranslationUnit TU,
if (NumTokens == 0 || !Tokens || !Cursors)
return;
// Any token we don't specifically annotate will have a NULL cursor.
CXCursor C = clang_getNullCursor();
for (unsigned I = 0; I != NumTokens; ++I)
Cursors[I] = C;
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU);
if (!CXXUnit) {
// Any token we don't specifically annotate will have a NULL cursor.
const CXCursor &C = clang_getNullCursor();
for (unsigned I = 0; I != NumTokens; ++I)
Cursors[I] = C;
if (!CXXUnit)
return;
}
ASTUnit::ConcurrencyCheck Check(*CXXUnit);