aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Lex/CodeCompletionHandler.h7
-rw-r--r--include/clang/Lex/Preprocessor.h5
-rw-r--r--include/clang/Parse/Parser.h1
-rw-r--r--include/clang/Sema/Action.h11
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h7
-rw-r--r--include/clang/Sema/Sema.h1
-rw-r--r--lib/Frontend/ASTUnit.cpp27
-rw-r--r--lib/Lex/PPDirectives.cpp7
-rw-r--r--lib/Lex/PPExpressions.cpp9
-rw-r--r--lib/Parse/Parser.cpp4
-rw-r--r--lib/Sema/SemaCodeComplete.cpp24
-rw-r--r--test/Index/complete-preprocessor.m12
12 files changed, 107 insertions, 8 deletions
diff --git a/include/clang/Lex/CodeCompletionHandler.h b/include/clang/Lex/CodeCompletionHandler.h
index 4cc3b12d47..ee02a227e6 100644
--- a/include/clang/Lex/CodeCompletionHandler.h
+++ b/include/clang/Lex/CodeCompletionHandler.h
@@ -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) { }
};
}
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 712feaa425..543cb74226 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -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;
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 83b42fd172..e485963026 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -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
diff --git a/include/clang/Sema/Action.h b/include/clang/Sema/Action.h
index d407037515..aebb2b4d2b 100644
--- a/include/clang/Sema/Action.h
+++ b/include/clang/Sema/Action.h
@@ -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) {
+ }
//@}
};
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index 59d8a4fd04..f9cf484953 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -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:
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index b4449ff45c..1ad6ca690a 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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);
//@}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 8a15f92045..384edb4502 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -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];
}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index e0729f123f..8da7def9ed 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -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);
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 9920c4cb7c..73f3d4ee7a 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -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();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 230506d85f..13db742f18 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -1139,3 +1139,7 @@ void Parser::CodeCompleteDirective(bool InConditional) {
void Parser::CodeCompleteInConditionalExclusion() {
Actions.CodeCompleteInPreprocessorConditionalExclusion(getCurScope());
}
+
+void Parser::CodeCompleteMacroName(bool IsDefinition) {
+ Actions.CodeCompletePreprocessorMacroName(getCurScope(), IsDefinition);
+}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 14043e8b62..97742654ae 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -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);
diff --git a/test/Index/complete-preprocessor.m b/test/Index/complete-preprocessor.m
index b951c1622e..14c4c150b3 100644
--- a/test/Index/complete-preprocessor.m
+++ b/test/Index/complete-preprocessor.m
@@ -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