From: Argyrios Kyrtzidis Date: Fri, 21 Dec 2012 01:17:20 +0000 (+0000) Subject: [libclang] Make sure we can code-complete inside a macro argument even though X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cd0fd18909e3b89ed6f2cc1118809003db64e67a;p=clang [libclang] Make sure we can code-complete inside a macro argument even though the macro invocation is not fully formed. rdar://11290992 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170824 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index d2f1b5f05d..a523612fbd 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -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 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(" & "#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); diff --git a/test/Index/complete-macro-args.c b/test/Index/complete-macro-args.c index ca36af1f10..2f3833d989 100644 --- a/test/Index/complete-macro-args.c +++ b/test/Index/complete-macro-args.c @@ -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)