mirror of
https://github.com/intel/llvm.git
synced 2026-01-27 14:50:42 +08:00
Implement preprocessor code completion where a macro name is expected,
e.g., after #ifdef/#ifndef or #undef, or inside a defined <macroname> expression in a preprocessor conditional. llvm-svn: 111954
This commit is contained in:
@@ -35,6 +35,13 @@ public:
|
||||
/// \brief Callback invoked when performing code completion within a block of
|
||||
/// code that was excluded due to preprocessor conditionals.
|
||||
virtual void CodeCompleteInConditionalExclusion() { }
|
||||
|
||||
/// \brief Callback invoked when performing code completion in a context
|
||||
/// where the name of a macro is expected.
|
||||
///
|
||||
/// \param IsDefinition Whether this is the definition of a macro, e.g.,
|
||||
/// in a #define.
|
||||
virtual void CodeCompleteMacroName(bool IsDefinition) { }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -382,6 +382,11 @@ public:
|
||||
CodeComplete = &Handler;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the current code-completion handler.
|
||||
CodeCompletionHandler *getCodeCompletionHandler() const {
|
||||
return CodeComplete;
|
||||
}
|
||||
|
||||
/// \brief Clear out the code completion handler.
|
||||
void clearCodeCompletionHandler() {
|
||||
CodeComplete = 0;
|
||||
|
||||
@@ -1535,6 +1535,7 @@ private:
|
||||
// Preprocessor code-completion pass-through
|
||||
virtual void CodeCompleteDirective(bool InConditional);
|
||||
virtual void CodeCompleteInConditionalExclusion();
|
||||
virtual void CodeCompleteMacroName(bool IsDefinition);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
@@ -3215,6 +3215,17 @@ public:
|
||||
/// \brief Code completion while in an area of the translation unit that was
|
||||
/// excluded due to preprocessor conditionals.
|
||||
virtual void CodeCompleteInPreprocessorConditionalExclusion(Scope *S) { }
|
||||
|
||||
/// \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) {
|
||||
}
|
||||
//@}
|
||||
};
|
||||
|
||||
|
||||
@@ -169,7 +169,12 @@ public:
|
||||
CCC_Name,
|
||||
/// \brief Code completion occurred where a new name is expected and a
|
||||
/// qualified name is permissible.
|
||||
CCC_PotentiallyQualifiedName
|
||||
CCC_PotentiallyQualifiedName,
|
||||
/// \brief Code completion occurred where an macro is being defined.
|
||||
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
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
@@ -4692,6 +4692,7 @@ public:
|
||||
unsigned NumSelIdents);
|
||||
virtual void CodeCompletePreprocessorDirective(Scope *S, bool InConditional);
|
||||
virtual void CodeCompleteInPreprocessorConditionalExclusion(Scope *S);
|
||||
virtual void CodeCompletePreprocessorMacroName(Scope *S, bool IsDefinition);
|
||||
void GatherGlobalCodeCompletions(
|
||||
llvm::SmallVectorImpl<CodeCompleteConsumer::Result> &Results);
|
||||
//@}
|
||||
|
||||
@@ -277,7 +277,8 @@ void ASTUnit::CacheCodeCompletionResults() {
|
||||
| (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
|
||||
| (1 << (CodeCompletionContext::CCC_Statement - 1))
|
||||
| (1 << (CodeCompletionContext::CCC_Expression - 1))
|
||||
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
|
||||
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
|
||||
| (1 << (CodeCompletionContext::CCC_MacroNameUse - 1));
|
||||
|
||||
CachedResult.Priority = Results[I].Priority;
|
||||
CachedResult.Kind = Results[I].CursorKind;
|
||||
@@ -1547,7 +1548,9 @@ void CalculateHiddenNames(const CodeCompletionContext &Context,
|
||||
break;
|
||||
|
||||
case CodeCompletionContext::CCC_ObjCProtocolName:
|
||||
// If we're just looking for protocol names, nothing can hide them.
|
||||
case CodeCompletionContext::CCC_MacroName:
|
||||
case CodeCompletionContext::CCC_MacroNameUse:
|
||||
// If we're just looking for protocol or macro names, nothing can hide them.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1595,7 +1598,7 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
|
||||
|
||||
// Contains the set of names that are hidden by "local" completion results.
|
||||
llvm::StringSet<> HiddenNames;
|
||||
|
||||
llvm::SmallVector<CodeCompletionString *, 4> StringsToDestroy;
|
||||
typedef CodeCompleteConsumer::Result Result;
|
||||
llvm::SmallVector<Result, 8> AllResults;
|
||||
for (ASTUnit::cached_completion_iterator
|
||||
@@ -1623,10 +1626,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
|
||||
|
||||
// Adjust priority based on similar type classes.
|
||||
unsigned Priority = C->Priority;
|
||||
CodeCompletionString *Completion = C->Completion;
|
||||
if (!Context.getPreferredType().isNull()) {
|
||||
if (C->Kind == CXCursor_MacroDefinition) {
|
||||
Priority = getMacroUsagePriority(C->Completion->getTypedText(),
|
||||
Context.getPreferredType()->isAnyPointerType());
|
||||
Context.getPreferredType()->isAnyPointerType());
|
||||
} else if (C->Type) {
|
||||
CanQualType Expected
|
||||
= S.Context.getCanonicalType(
|
||||
@@ -1646,7 +1650,17 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
|
||||
}
|
||||
}
|
||||
|
||||
AllResults.push_back(Result(C->Completion, Priority, C->Kind,
|
||||
// Adjust the completion string, if required.
|
||||
if (C->Kind == CXCursor_MacroDefinition &&
|
||||
Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) {
|
||||
// Create a new code-completion string that just contains the
|
||||
// macro name, without its arguments.
|
||||
Completion = new CodeCompletionString;
|
||||
Completion->AddTypedTextChunk(C->Completion->getTypedText());
|
||||
StringsToDestroy.push_back(Completion);
|
||||
}
|
||||
|
||||
AllResults.push_back(Result(Completion, Priority, C->Kind,
|
||||
C->Availability));
|
||||
}
|
||||
|
||||
@@ -1659,6 +1673,9 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
|
||||
|
||||
Next.ProcessCodeCompleteResults(S, Context, AllResults.data(),
|
||||
AllResults.size());
|
||||
|
||||
for (unsigned I = 0, N = StringsToDestroy.size(); I != N; ++I)
|
||||
delete StringsToDestroy[I];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -75,6 +75,13 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
|
||||
// Read the token, don't allow macro expansion on it.
|
||||
LexUnexpandedToken(MacroNameTok);
|
||||
|
||||
if (MacroNameTok.is(tok::code_completion)) {
|
||||
if (CodeComplete)
|
||||
CodeComplete->CodeCompleteMacroName(isDefineUndef == 1);
|
||||
LexUnexpandedToken(MacroNameTok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Missing macro name?
|
||||
if (MacroNameTok.is(tok::eom)) {
|
||||
Diag(MacroNameTok, diag::err_pp_missing_macro_name);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Lex/CodeCompletionHandler.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
@@ -92,6 +93,12 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
|
||||
PP.LexUnexpandedToken(PeekTok);
|
||||
}
|
||||
|
||||
if (PeekTok.is(tok::code_completion)) {
|
||||
if (PP.getCodeCompletionHandler())
|
||||
PP.getCodeCompletionHandler()->CodeCompleteMacroName(false);
|
||||
PP.LexUnexpandedToken(PeekTok);
|
||||
}
|
||||
|
||||
// If we don't have a pp-identifier now, this is an error.
|
||||
if ((II = PeekTok.getIdentifierInfo()) == 0) {
|
||||
PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier);
|
||||
@@ -697,7 +704,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
|
||||
// Peek ahead one token.
|
||||
Token Tok;
|
||||
Lex(Tok);
|
||||
|
||||
|
||||
// C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t.
|
||||
unsigned BitWidth = getTargetInfo().getIntMaxTWidth();
|
||||
|
||||
|
||||
@@ -1139,3 +1139,7 @@ void Parser::CodeCompleteDirective(bool InConditional) {
|
||||
void Parser::CodeCompleteInConditionalExclusion() {
|
||||
Actions.CodeCompleteInPreprocessorConditionalExclusion(getCurScope());
|
||||
}
|
||||
|
||||
void Parser::CodeCompleteMacroName(bool IsDefinition) {
|
||||
Actions.CodeCompletePreprocessorMacroName(getCurScope(), IsDefinition);
|
||||
}
|
||||
|
||||
@@ -4787,6 +4787,30 @@ void Sema::CodeCompleteInPreprocessorConditionalExclusion(Scope *S) {
|
||||
CodeCompleteOrdinaryName(S, Action::PCC_RecoveryInFunction);
|
||||
}
|
||||
|
||||
void Sema::CodeCompletePreprocessorMacroName(Scope *S, bool IsDefinition) {
|
||||
typedef CodeCompleteConsumer::Result Result;
|
||||
ResultBuilder Results(*this);
|
||||
if (!IsDefinition && (!CodeCompleter || CodeCompleter->includeMacros())) {
|
||||
// Add just the names of macros, not their arguments.
|
||||
Results.EnterNewScope();
|
||||
for (Preprocessor::macro_iterator M = PP.macro_begin(),
|
||||
MEnd = PP.macro_end();
|
||||
M != MEnd; ++M) {
|
||||
CodeCompletionString *Pattern = new CodeCompletionString;
|
||||
Pattern->AddTypedTextChunk(M->first->getName());
|
||||
Results.AddResult(Pattern);
|
||||
}
|
||||
Results.ExitScope();
|
||||
} else if (IsDefinition) {
|
||||
// FIXME: Can we detect when the user just wrote an include guard above?
|
||||
}
|
||||
|
||||
HandleCodeCompleteResults(this, CodeCompleter,
|
||||
IsDefinition? CodeCompletionContext::CCC_MacroName
|
||||
: CodeCompletionContext::CCC_MacroNameUse,
|
||||
Results.data(), Results.size());
|
||||
}
|
||||
|
||||
void Sema::GatherGlobalCodeCompletions(
|
||||
llvm::SmallVectorImpl<CodeCompleteConsumer::Result> &Results) {
|
||||
ResultBuilder Builder(*this);
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
#if 1
|
||||
#endif
|
||||
|
||||
|
||||
#define FOO(a, b) a##b
|
||||
#define BAR
|
||||
#ifdef FOO
|
||||
#endif
|
||||
#if defined(FOO)
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
@@ -45,3 +50,8 @@
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText pragma}{HorizontalSpace }{Placeholder arguments} (30)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText undef}{HorizontalSpace }{Placeholder macro} (30)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText warning}{HorizontalSpace }{Placeholder message} (30)
|
||||
// RUN: c-index-test -code-completion-at=%s:9:8 %s | FileCheck -check-prefix=CHECK-CC3 %s
|
||||
// CHECK-CC3: NotImplemented:{TypedText BAR} (30)
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user