[libclang] Make sure we can code-complete inside a macro argument even though

the macro invocation is not fully formed.

rdar://11290992

llvm-svn: 170824
This commit is contained in:
Argyrios Kyrtzidis
2012-12-21 01:17:20 +00:00
parent 93f778d2bd
commit c1d9a67e2b
2 changed files with 35 additions and 14 deletions

View File

@@ -497,9 +497,13 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// argument is separated by an EOF token. Use a SmallVector so we can avoid
// heap allocations in the common case.
SmallVector<Token, 64> ArgTokens;
bool ContainsCodeCompletionTok = false;
unsigned NumActuals = 0;
while (Tok.isNot(tok::r_paren)) {
if (ContainsCodeCompletionTok && (Tok.is(tok::eof) || Tok.is(tok::eod)))
break;
assert((Tok.is(tok::l_paren) || Tok.is(tok::comma)) &&
"only expect argument separators here");
@@ -516,12 +520,16 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
LexUnexpandedToken(Tok);
if (Tok.is(tok::eof) || Tok.is(tok::eod)) { // "#if f(<eof>" & "#if f(\n"
Diag(MacroName, diag::err_unterm_macro_invoc);
Diag(MI->getDefinitionLoc(), diag::note_macro_here)
<< MacroName.getIdentifierInfo();
// Do not lose the EOF/EOD. Return it to the client.
MacroName = Tok;
return 0;
if (!ContainsCodeCompletionTok) {
Diag(MacroName, diag::err_unterm_macro_invoc);
Diag(MI->getDefinitionLoc(), diag::note_macro_here)
<< MacroName.getIdentifierInfo();
// Do not lose the EOF/EOD. Return it to the client.
MacroName = Tok;
return 0;
} else {
break;
}
} else if (Tok.is(tok::r_paren)) {
// If we found the ) token, the macro arg list is done.
if (NumParens-- == 0) {
@@ -552,6 +560,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (!MI->isEnabled())
Tok.setFlag(Token::DisableExpand);
} else if (Tok.is(tok::code_completion)) {
ContainsCodeCompletionTok = true;
if (CodeComplete)
CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(),
MI, NumActuals);
@@ -574,12 +583,14 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (ArgTokens.size() != ArgTokenStart)
ArgStartLoc = ArgTokens[ArgTokenStart].getLocation();
// Emit the diagnostic at the macro name in case there is a missing ).
// Emitting it at the , could be far away from the macro name.
Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
Diag(MI->getDefinitionLoc(), diag::note_macro_here)
<< MacroName.getIdentifierInfo();
return 0;
if (!ContainsCodeCompletionTok) {
// Emit the diagnostic at the macro name in case there is a missing ).
// Emitting it at the , could be far away from the macro name.
Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
Diag(MI->getDefinitionLoc(), diag::note_macro_here)
<< MacroName.getIdentifierInfo();
return 0;
}
}
// Empty arguments are standard in C99 and C++0x, and are supported as an extension in
@@ -639,7 +650,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// #define C(...) blah(a, ## __VA_ARGS__)
// A(x) B(x) C()
isVarargsElided = true;
} else {
} else if (!ContainsCodeCompletionTok) {
// Otherwise, emit the error.
Diag(Tok, diag::err_too_few_args_in_macro_invoc);
Diag(MI->getDefinitionLoc(), diag::note_macro_here)
@@ -659,7 +670,8 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (NumActuals == 0 && MinArgsExpected == 2)
ArgTokens.push_back(Tok);
} else if (NumActuals > MinArgsExpected && !MI->isVariadic()) {
} else if (NumActuals > MinArgsExpected && !MI->isVariadic() &&
!ContainsCodeCompletionTok) {
// Emit the diagnostic at the macro name in case there is a missing ).
// Emitting it at the , could be far away from the macro name.
Diag(MacroName, diag::err_too_many_args_in_macro_invoc);

View File

@@ -12,8 +12,17 @@ void test(struct Point *p) {
MACRO(p->x);
}
#define MACRO3(x,y,z) x
void test(struct Point *p) {
MACRO3(p->x);
MACRO3(p->x
}
// RUN: c-index-test -code-completion-at=%s:11:12 %s | FileCheck %s
// RUN: c-index-test -code-completion-at=%s:12:12 %s | FileCheck %s
// RUN: c-index-test -code-completion-at=%s:18:13 %s | FileCheck %s
// RUN: c-index-test -code-completion-at=%s:19:13 %s | FileCheck %s
// CHECK: FieldDecl:{ResultType float}{TypedText x} (35)
// CHECK-NEXT: FieldDecl:{ResultType float}{TypedText y} (35)
// CHECK-NEXT: FieldDecl:{ResultType float}{TypedText z} (35)