Implement code completion for preprocessor expressions and in macro
arguments. llvm-svn: 111976
This commit is contained in:
parent
3c884a014c
commit
ec00a26855
|
@ -16,6 +16,9 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
class IdentifierInfo;
|
||||
class MacroInfo;
|
||||
|
||||
/// \brief Callback handler that receives notifications when performing code
|
||||
/// completion within the preprocessor.
|
||||
class CodeCompletionHandler {
|
||||
|
@ -42,6 +45,16 @@ public:
|
|||
/// \param IsDefinition Whether this is the definition of a macro, e.g.,
|
||||
/// in a #define.
|
||||
virtual void CodeCompleteMacroName(bool IsDefinition) { }
|
||||
|
||||
/// \brief Callback invoked when performing code completion in a preprocessor
|
||||
/// expression, such as the condition of an #if or #elif directive.
|
||||
virtual void CodeCompletePreprocessorExpression() { }
|
||||
|
||||
/// \brief Callback invoked when performing code completion inside a
|
||||
/// function-like macro argument.
|
||||
virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro,
|
||||
MacroInfo *MacroInfo,
|
||||
unsigned ArgumentIndex) { }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1536,6 +1536,10 @@ private:
|
|||
virtual void CodeCompleteDirective(bool InConditional);
|
||||
virtual void CodeCompleteInConditionalExclusion();
|
||||
virtual void CodeCompleteMacroName(bool IsDefinition);
|
||||
virtual void CodeCompletePreprocessorExpression();
|
||||
virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro,
|
||||
MacroInfo *MacroInfo,
|
||||
unsigned ArgumentIndex);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -43,7 +43,8 @@ namespace clang {
|
|||
// Lex.
|
||||
class Preprocessor;
|
||||
class Token;
|
||||
|
||||
class MacroInfo;
|
||||
|
||||
/// Action - As the parser reads the input file and recognizes the productions
|
||||
/// of the grammar, it invokes methods on this class to turn the parsed input
|
||||
/// into something useful: e.g. a parse tree.
|
||||
|
@ -3207,9 +3208,8 @@ public:
|
|||
|
||||
/// \brief Code completion for a preprocessor directive.
|
||||
///
|
||||
/// \brief S The scope in which the preprocessor directive is being parsed.
|
||||
/// \brief InConditional Whether we're inside a preprocessor conditional.
|
||||
virtual void CodeCompletePreprocessorDirective(Scope *S, bool InConditional) {
|
||||
virtual void CodeCompletePreprocessorDirective(bool InConditional) {
|
||||
}
|
||||
|
||||
/// \brief Code completion while in an area of the translation unit that was
|
||||
|
@ -3219,13 +3219,31 @@ public:
|
|||
/// \brief Code completion in the preprocessor where an already-defined
|
||||
/// macro name is expected, e.g., an #ifdef or #undef.
|
||||
///
|
||||
/// \param S The scope in which the macro name occurs.
|
||||
///
|
||||
/// \param IsDefinition Whether this code completion for a macro name occurs
|
||||
/// in a definition of the macro (#define) or in another use that already
|
||||
/// expects that the macro is defined (e.g., #undef or #ifdef).
|
||||
virtual void CodeCompletePreprocessorMacroName(Scope *S, bool IsDefinition) {
|
||||
virtual void CodeCompletePreprocessorMacroName(bool IsDefinition) {
|
||||
}
|
||||
|
||||
/// \brief Callback invoked when performing code completion in a preprocessor
|
||||
/// expression, such as the condition of an #if or #elif directive.
|
||||
virtual void CodeCompletePreprocessorExpression() { }
|
||||
|
||||
/// \brief Callback invoked when performing code completion inside a
|
||||
/// function-like macro argument.
|
||||
///
|
||||
/// \param S The scope in which this macro is being expanded.
|
||||
///
|
||||
/// \param Macro The name of the macro that is going to be expanded.
|
||||
///
|
||||
/// \param MacroInfo Information about the macro that is going to be
|
||||
/// expanded.
|
||||
///
|
||||
/// \param Argument The argument in which the code-completion token occurs.
|
||||
virtual void CodeCompletePreprocessorMacroArgument(Scope *S,
|
||||
IdentifierInfo *Macro,
|
||||
MacroInfo *MacroInfo,
|
||||
unsigned Argument) { }
|
||||
//@}
|
||||
};
|
||||
|
||||
|
|
|
@ -174,7 +174,9 @@ public:
|
|||
CCC_MacroName,
|
||||
/// \brief Code completion occurred where a macro name is expected
|
||||
/// (without any arguments, in the case of a function-like macro).
|
||||
CCC_MacroNameUse
|
||||
CCC_MacroNameUse,
|
||||
/// \brief Code completion occurred within a preprocessor expression.
|
||||
CCC_PreprocessorExpression
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -4633,9 +4633,14 @@ public:
|
|||
ParsedType ReturnType,
|
||||
IdentifierInfo **SelIdents,
|
||||
unsigned NumSelIdents);
|
||||
virtual void CodeCompletePreprocessorDirective(Scope *S, bool InConditional);
|
||||
virtual void CodeCompletePreprocessorDirective(bool InConditional);
|
||||
virtual void CodeCompleteInPreprocessorConditionalExclusion(Scope *S);
|
||||
virtual void CodeCompletePreprocessorMacroName(Scope *S, bool IsDefinition);
|
||||
virtual void CodeCompletePreprocessorMacroName(bool IsDefinition);
|
||||
virtual void CodeCompletePreprocessorExpression();
|
||||
virtual void CodeCompletePreprocessorMacroArgument(Scope *S,
|
||||
IdentifierInfo *Macro,
|
||||
MacroInfo *MacroInfo,
|
||||
unsigned Argument);
|
||||
void GatherGlobalCodeCompletions(
|
||||
llvm::SmallVectorImpl<CodeCompleteConsumer::Result> &Results);
|
||||
//@}
|
||||
|
|
|
@ -278,7 +278,8 @@ void ASTUnit::CacheCodeCompletionResults() {
|
|||
| (1 << (CodeCompletionContext::CCC_Statement - 1))
|
||||
| (1 << (CodeCompletionContext::CCC_Expression - 1))
|
||||
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
|
||||
| (1 << (CodeCompletionContext::CCC_MacroNameUse - 1));
|
||||
| (1 << (CodeCompletionContext::CCC_MacroNameUse - 1))
|
||||
| (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1));
|
||||
|
||||
CachedResult.Priority = Results[I].Priority;
|
||||
CachedResult.Kind = Results[I].CursorKind;
|
||||
|
@ -1550,6 +1551,7 @@ void CalculateHiddenNames(const CodeCompletionContext &Context,
|
|||
case CodeCompletionContext::CCC_ObjCProtocolName:
|
||||
case CodeCompletionContext::CCC_MacroName:
|
||||
case CodeCompletionContext::CCC_MacroNameUse:
|
||||
case CodeCompletionContext::CCC_PreprocessorExpression:
|
||||
// If we're just looking for protocol or macro names, nothing can hide them.
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -149,6 +149,12 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
|
|||
bool ValueLive, Preprocessor &PP) {
|
||||
DT.State = DefinedTracker::Unknown;
|
||||
|
||||
if (PeekTok.is(tok::code_completion)) {
|
||||
if (PP.getCodeCompletionHandler())
|
||||
PP.getCodeCompletionHandler()->CodeCompletePreprocessorExpression();
|
||||
PP.LexUnexpandedToken(PeekTok);
|
||||
}
|
||||
|
||||
// If this token's spelling is a pp-identifier, check to see if it is
|
||||
// 'defined' or if it is a macro. Note that we check here because many
|
||||
// keywords are pp-identifiers, so we can't check the kind.
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "clang/Lex/CodeCompletionHandler.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdio>
|
||||
|
@ -323,6 +324,13 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
|
|||
// an argument value in a macro could expand to ',' or '(' or ')'.
|
||||
LexUnexpandedToken(Tok);
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
if (CodeComplete)
|
||||
CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(),
|
||||
MI, NumActuals);
|
||||
LexUnexpandedToken(Tok);
|
||||
}
|
||||
|
||||
if (Tok.is(tok::eof) || Tok.is(tok::eom)) { // "#if f(<eof>" & "#if f(\n"
|
||||
Diag(MacroName, diag::err_unterm_macro_invoc);
|
||||
// Do not lose the EOF/EOM. Return it to the client.
|
||||
|
|
|
@ -1133,7 +1133,7 @@ void Parser::FieldCallback::_anchor() {
|
|||
// Code-completion pass-through functions
|
||||
|
||||
void Parser::CodeCompleteDirective(bool InConditional) {
|
||||
Actions.CodeCompletePreprocessorDirective(getCurScope(), InConditional);
|
||||
Actions.CodeCompletePreprocessorDirective(InConditional);
|
||||
}
|
||||
|
||||
void Parser::CodeCompleteInConditionalExclusion() {
|
||||
|
@ -1141,5 +1141,16 @@ void Parser::CodeCompleteInConditionalExclusion() {
|
|||
}
|
||||
|
||||
void Parser::CodeCompleteMacroName(bool IsDefinition) {
|
||||
Actions.CodeCompletePreprocessorMacroName(getCurScope(), IsDefinition);
|
||||
Actions.CodeCompletePreprocessorMacroName(IsDefinition);
|
||||
}
|
||||
|
||||
void Parser::CodeCompletePreprocessorExpression() {
|
||||
Actions.CodeCompletePreprocessorExpression();
|
||||
}
|
||||
|
||||
void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro,
|
||||
MacroInfo *MacroInfo,
|
||||
unsigned ArgumentIndex) {
|
||||
Actions.CodeCompletePreprocessorMacroArgument(getCurScope(), Macro, MacroInfo,
|
||||
ArgumentIndex);
|
||||
}
|
||||
|
|
|
@ -4608,7 +4608,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
|
|||
Results.data(),Results.size());
|
||||
}
|
||||
|
||||
void Sema::CodeCompletePreprocessorDirective(Scope *S, bool InConditional) {
|
||||
void Sema::CodeCompletePreprocessorDirective(bool InConditional) {
|
||||
ResultBuilder Results(*this);
|
||||
Results.EnterNewScope();
|
||||
|
||||
|
@ -4785,11 +4785,12 @@ void Sema::CodeCompletePreprocessorDirective(Scope *S, bool InConditional) {
|
|||
}
|
||||
|
||||
void Sema::CodeCompleteInPreprocessorConditionalExclusion(Scope *S) {
|
||||
CodeCompleteOrdinaryName(S, Action::PCC_RecoveryInFunction);
|
||||
CodeCompleteOrdinaryName(S,
|
||||
S->getFnParent()? Action::PCC_RecoveryInFunction
|
||||
: Action::PCC_Namespace);
|
||||
}
|
||||
|
||||
void Sema::CodeCompletePreprocessorMacroName(Scope *S, bool IsDefinition) {
|
||||
typedef CodeCompleteConsumer::Result Result;
|
||||
void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) {
|
||||
ResultBuilder Results(*this);
|
||||
if (!IsDefinition && (!CodeCompleter || CodeCompleter->includeMacros())) {
|
||||
// Add just the names of macros, not their arguments.
|
||||
|
@ -4812,6 +4813,40 @@ void Sema::CodeCompletePreprocessorMacroName(Scope *S, bool IsDefinition) {
|
|||
Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void Sema::CodeCompletePreprocessorExpression() {
|
||||
ResultBuilder Results(*this);
|
||||
|
||||
if (!CodeCompleter || CodeCompleter->includeMacros())
|
||||
AddMacroResults(PP, Results);
|
||||
|
||||
// defined (<macro>)
|
||||
Results.EnterNewScope();
|
||||
CodeCompletionString *Pattern = new CodeCompletionString;
|
||||
Pattern->AddTypedTextChunk("defined");
|
||||
Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
|
||||
Pattern->AddPlaceholderChunk("macro");
|
||||
Pattern->AddChunk(CodeCompletionString::CK_RightParen);
|
||||
Results.AddResult(Pattern);
|
||||
Results.ExitScope();
|
||||
|
||||
HandleCodeCompleteResults(this, CodeCompleter,
|
||||
CodeCompletionContext::CCC_PreprocessorExpression,
|
||||
Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void Sema::CodeCompletePreprocessorMacroArgument(Scope *S,
|
||||
IdentifierInfo *Macro,
|
||||
MacroInfo *MacroInfo,
|
||||
unsigned Argument) {
|
||||
// FIXME: In the future, we could provide "overload" results, much like we
|
||||
// do for function calls.
|
||||
|
||||
CodeCompleteOrdinaryName(S,
|
||||
S->getFnParent()? Action::PCC_RecoveryInFunction
|
||||
: Action::PCC_Namespace);
|
||||
}
|
||||
|
||||
void Sema::GatherGlobalCodeCompletions(
|
||||
llvm::SmallVectorImpl<CodeCompleteConsumer::Result> &Results) {
|
||||
ResultBuilder Builder(*this);
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#if defined(FOO)
|
||||
#endif
|
||||
|
||||
FOO(in,t) value;
|
||||
|
||||
// RUN: c-index-test -code-completion-at=%s:4:2 %s | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// CHECK-CC1: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro} (30)
|
||||
// CHECK-CC1-NEXT: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro}{LeftParen (}{Placeholder args}{RightParen )} (30)
|
||||
|
@ -55,3 +57,18 @@
|
|||
// CHECK-CC3: NotImplemented:{TypedText FOO} (30)
|
||||
// RUN: c-index-test -code-completion-at=%s:11:12 %s | FileCheck -check-prefix=CHECK-CC3 %s
|
||||
// RUN: c-index-test -code-completion-at=%s:11:13 %s | FileCheck -check-prefix=CHECK-CC3 %s
|
||||
// RUN: c-index-test -code-completion-at=%s:11:5 %s | FileCheck -check-prefix=CHECK-CC4 %s
|
||||
// CHECK-CC4: macro definition:{TypedText BAR} (70)
|
||||
// CHECK-CC4: macro definition:{TypedText FOO}{LeftParen (}{Placeholder a}{Comma , }{Placeholder b}{RightParen )} (70)
|
||||
// RUN: c-index-test -code-completion-at=%s:14:5 %s | FileCheck -check-prefix=CHECK-CC5 %s
|
||||
// CHECK-CC5: NotImplemented:{TypedText const} (40)
|
||||
// CHECK-CC5: NotImplemented:{TypedText double} (40)
|
||||
// CHECK-CC5: NotImplemented:{TypedText enum} (40)
|
||||
// CHECK-CC5: NotImplemented:{TypedText extern} (30)
|
||||
// CHECK-CC5: NotImplemented:{TypedText float} (40)
|
||||
// CHECK-CC5: macro definition:{TypedText FOO}{LeftParen (}{Placeholder a}{Comma , }{Placeholder b}{RightParen )} (70)
|
||||
// CHECK-CC5: macro definition:{TypedText i386} (70)
|
||||
// CHECK-CC5: TypedefDecl:{TypedText id} (40)
|
||||
// CHECK-CC5: NotImplemented:{TypedText inline} (30)
|
||||
// CHECK-CC5: NotImplemented:{TypedText int} (40)
|
||||
// CHECK-CC5: NotImplemented:{TypedText long} (40)
|
||||
|
|
Loading…
Reference in New Issue