Introduce basic code-completion support for preprocessor directives,
e.g., after a "#" we'll suggest #if, #ifdef, etc.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111943 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Lex/CodeCompletionHandler.h b/include/clang/Lex/CodeCompletionHandler.h
new file mode 100644
index 0000000..4cc3b12
--- /dev/null
+++ b/include/clang/Lex/CodeCompletionHandler.h
@@ -0,0 +1,42 @@
+//===--- CodeCompletionHandler.h - Preprocessor code completion -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CodeCompletionHandler interface, which provides
+// code-completion callbacks for the preprocessor.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H
+#define LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H
+
+namespace clang {
+
+/// \brief Callback handler that receives notifications when performing code
+/// completion within the preprocessor.
+class CodeCompletionHandler {
+public:
+ virtual ~CodeCompletionHandler();
+
+ /// \brief Callback invoked when performing code completion for a preprocessor
+ /// directive.
+ ///
+ /// This callback will be invoked when the preprocessor processes a '#' at the
+ /// start of a line, followed by the code-completion token.
+ ///
+ /// \param InConditional Whether we're inside a preprocessor conditional
+ /// already.
+ virtual void CodeCompleteDirective(bool InConditional) { }
+
+ /// \brief Callback invoked when performing code completion within a block of
+ /// code that was excluded due to preprocessor conditionals.
+ virtual void CodeCompleteInConditionalExclusion() { }
+};
+
+}
+
+#endif // LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 8bf0df3..712feaa 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -42,6 +42,7 @@
class ScratchBuffer;
class TargetInfo;
class PPCallbacks;
+class CodeCompletionHandler;
class DirectoryLookup;
class PreprocessingRecord;
@@ -131,6 +132,9 @@
/// with this preprocessor.
std::vector<CommentHandler *> CommentHandlers;
+ /// \brief The code-completion handler.
+ CodeCompletionHandler *CodeComplete;
+
/// \brief The file that we're performing code-completion for, if any.
const FileEntry *CodeCompletionFile;
@@ -373,6 +377,16 @@
/// It is an error to remove a handler that has not been registered.
void RemoveCommentHandler(CommentHandler *Handler);
+ /// \brief Set the code completion handler to the given object.
+ void setCodeCompletionHandler(CodeCompletionHandler &Handler) {
+ CodeComplete = &Handler;
+ }
+
+ /// \brief Clear out the code completion handler.
+ void clearCodeCompletionHandler() {
+ CodeComplete = 0;
+ }
+
/// \brief Retrieve the preprocessing record, or NULL if there is no
/// preprocessing record.
PreprocessingRecord *getPreprocessingRecord() const { return Record; }
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index ceaeb34..83b42fd 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -16,6 +16,7 @@
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Sema/Action.h"
#include "clang/Sema/DeclSpec.h"
#include "llvm/ADT/OwningPtr.h"
@@ -70,7 +71,7 @@
/// parsing units of the grammar, productions are invoked to handle whatever has
/// been read.
///
-class Parser {
+class Parser : public CodeCompletionHandler {
friend class PragmaUnusedHandler;
friend class ColonProtectionRAIIObject;
friend class ParenBraceBracketBalancer;
@@ -1529,6 +1530,11 @@
//===--------------------------------------------------------------------===//
// GNU G++: Type Traits [Type-Traits.html in the GCC manual]
ExprResult ParseUnaryTypeTrait();
+
+ //===--------------------------------------------------------------------===//
+ // Preprocessor code-completion pass-through
+ virtual void CodeCompleteDirective(bool InConditional);
+ virtual void CodeCompleteInConditionalExclusion();
};
} // end namespace clang
diff --git a/include/clang/Sema/Action.h b/include/clang/Sema/Action.h
index 1d3d460..d407037 100644
--- a/include/clang/Sema/Action.h
+++ b/include/clang/Sema/Action.h
@@ -3205,6 +3205,16 @@
IdentifierInfo **SelIdents,
unsigned NumSelIdents) { }
+ /// \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) {
+ }
+
+ /// \brief Code completion while in an area of the translation unit that was
+ /// excluded due to preprocessor conditionals.
+ virtual void CodeCompleteInPreprocessorConditionalExclusion(Scope *S) { }
//@}
};
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 3991bce..b4449ff 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -4690,6 +4690,8 @@
ParsedType ReturnType,
IdentifierInfo **SelIdents,
unsigned NumSelIdents);
+ virtual void CodeCompletePreprocessorDirective(Scope *S, bool InConditional);
+ virtual void CodeCompleteInPreprocessorConditionalExclusion(Scope *S);
void GatherGlobalCodeCompletions(
llvm::SmallVectorImpl<CodeCompleteConsumer::Result> &Results);
//@}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 9a96934..3a77bbb 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1523,6 +1523,22 @@
/// This returns true if Result contains a token, false if PP.Lex should be
/// called again.
bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
+ // Check if we are performing code completion.
+ if (PP && PP->isCodeCompletionFile(FileLoc)) {
+ // We're at the end of the file, but we've been asked to consider the
+ // end of the file to be a code-completion token. Return the
+ // code-completion token.
+ Result.startToken();
+ FormTokenWithChars(Result, CurPtr, tok::code_completion);
+
+ // Only do the eof -> code_completion translation once.
+ PP->SetCodeCompletionPoint(0, 0, 0);
+
+ // Silence any diagnostics that occur once we hit the code-completion point.
+ PP->getDiagnostics().setSuppressAllDiagnostics(true);
+ return true;
+ }
+
// If we hit the end of the file while parsing a preprocessor directive,
// end the preprocessor directive first. The next token returned will
// then be the end of file.
@@ -1545,25 +1561,9 @@
FormTokenWithChars(Result, BufferEnd, tok::eof);
return true;
}
-
- // Otherwise, check if we are code-completing, then issue diagnostics for
- // unterminated #if and missing newline.
-
- if (PP && PP->isCodeCompletionFile(FileLoc)) {
- // We're at the end of the file, but we've been asked to consider the
- // end of the file to be a code-completion token. Return the
- // code-completion token.
- Result.startToken();
- FormTokenWithChars(Result, CurPtr, tok::code_completion);
-
- // Only do the eof -> code_completion translation once.
- PP->SetCodeCompletionPoint(0, 0, 0);
-
- // Silence any diagnostics that occur once we hit the code-completion point.
- PP->getDiagnostics().setSuppressAllDiagnostics(true);
- return true;
- }
+ // Issue diagnostics for unterminated #if and missing newline.
+
// If we are in a #if directive, emit an error.
while (!ConditionalStack.empty()) {
if (!PP->isCodeCompletionFile(FileLoc))
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index e000c54..e0729f1 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -16,6 +16,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/APInt.h"
@@ -177,6 +178,12 @@
while (1) {
CurLexer->Lex(Tok);
+ if (Tok.is(tok::code_completion)) {
+ if (CodeComplete)
+ CodeComplete->CodeCompleteInConditionalExclusion();
+ continue;
+ }
+
// If this is the end of the buffer, we have an error.
if (Tok.is(tok::eof)) {
// Emit errors for each unterminated conditional on the stack, including
@@ -522,7 +529,11 @@
// Handle stuff like "# /*foo*/ define X" in -E -C mode.
LexUnexpandedToken(Result);
goto TryAgain;
-
+ case tok::code_completion:
+ if (CodeComplete)
+ CodeComplete->CodeCompleteDirective(
+ CurPPLexer->getConditionalStackDepth() > 0);
+ return;
case tok::numeric_constant: // # 7 GNU line marker directive.
if (getLangOptions().AsmPreprocessor)
break; // # 4 is not a preprocessor directive in .S files.
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index d3959aa..04de68b 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -34,6 +34,7 @@
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/ScratchBuffer.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -53,9 +54,9 @@
bool OwnsHeaders)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0),
- Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0),
- SkipMainFilePreamble(0, true), CurPPLexer(0), CurDirLookup(0), Callbacks(0),
- MacroArgCache(0), Record(0) {
+ Identifiers(opts, IILookup), BuiltinInfo(Target), CodeComplete(0),
+ CodeCompletionFile(0), SkipMainFilePreamble(0, true), CurPPLexer(0),
+ CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0) {
ScratchBuf = new ScratchBuffer(SourceMgr);
CounterValue = 0; // __COUNTER__ starts at 0.
OwnsHeaderSearch = OwnsHeaders;
@@ -646,6 +647,8 @@
CommentHandler::~CommentHandler() { }
+CodeCompletionHandler::~CodeCompletionHandler() { }
+
void Preprocessor::createPreprocessingRecord() {
if (Record)
return;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 8fd1e48..230506d 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -50,6 +50,8 @@
WeakHandler.reset(new PragmaWeakHandler(actions));
PP.AddPragmaHandler(WeakHandler.get());
+
+ PP.setCodeCompletionHandler(*this);
}
/// If a crash happens while the parser is active, print out a line indicating
@@ -316,6 +318,7 @@
UnusedHandler.reset();
PP.RemovePragmaHandler(WeakHandler.get());
WeakHandler.reset();
+ PP.clearCodeCompletionHandler();
}
/// Initialize - Warm up the parser.
@@ -1126,3 +1129,13 @@
// performance-sensitive.
void Parser::FieldCallback::_anchor() {
}
+
+// Code-completion pass-through functions
+
+void Parser::CodeCompleteDirective(bool InConditional) {
+ Actions.CodeCompletePreprocessorDirective(getCurScope(), InConditional);
+}
+
+void Parser::CodeCompleteInConditionalExclusion() {
+ Actions.CodeCompleteInPreprocessorConditionalExclusion(getCurScope());
+}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 082ebcf..14043e8 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -4607,6 +4607,186 @@
Results.data(),Results.size());
}
+void Sema::CodeCompletePreprocessorDirective(Scope *S, bool InConditional) {
+ ResultBuilder Results(*this);
+ Results.EnterNewScope();
+
+ // #if <condition>
+ CodeCompletionString *Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("if");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("condition");
+ Results.AddResult(Pattern);
+
+ // #ifdef <macro>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("ifdef");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("macro");
+ Results.AddResult(Pattern);
+
+ // #ifndef <macro>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("ifndef");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("macro");
+ Results.AddResult(Pattern);
+
+ if (InConditional) {
+ // #elif <condition>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("elif");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("condition");
+ Results.AddResult(Pattern);
+
+ // #else
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("else");
+ Results.AddResult(Pattern);
+
+ // #endif
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("endif");
+ Results.AddResult(Pattern);
+ }
+
+ // #include "header"
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("include");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("\"");
+ Pattern->AddPlaceholderChunk("header");
+ Pattern->AddTextChunk("\"");
+ Results.AddResult(Pattern);
+
+ // #include <header>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("include");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("<");
+ Pattern->AddPlaceholderChunk("header");
+ Pattern->AddTextChunk(">");
+ Results.AddResult(Pattern);
+
+ // #define <macro>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("define");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("macro");
+ Results.AddResult(Pattern);
+
+ // #define <macro>(<args>)
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("define");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("macro");
+ Pattern->AddChunk(CodeCompletionString::CK_LeftParen);
+ Pattern->AddPlaceholderChunk("args");
+ Pattern->AddChunk(CodeCompletionString::CK_RightParen);
+ Results.AddResult(Pattern);
+
+ // #undef <macro>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("undef");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("macro");
+ Results.AddResult(Pattern);
+
+ // #line <number>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("line");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("number");
+ Results.AddResult(Pattern);
+
+ // #line <number> "filename"
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("line");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("number");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("\"");
+ Pattern->AddPlaceholderChunk("filename");
+ Pattern->AddTextChunk("\"");
+ Results.AddResult(Pattern);
+
+ // #error <message>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("error");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("message");
+ Results.AddResult(Pattern);
+
+ // #pragma <arguments>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("pragma");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("arguments");
+ Results.AddResult(Pattern);
+
+ if (getLangOptions().ObjC1) {
+ // #import "header"
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("import");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("\"");
+ Pattern->AddPlaceholderChunk("header");
+ Pattern->AddTextChunk("\"");
+ Results.AddResult(Pattern);
+
+ // #import <header>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("import");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("<");
+ Pattern->AddPlaceholderChunk("header");
+ Pattern->AddTextChunk(">");
+ Results.AddResult(Pattern);
+ }
+
+ // #include_next "header"
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("include_next");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("\"");
+ Pattern->AddPlaceholderChunk("header");
+ Pattern->AddTextChunk("\"");
+ Results.AddResult(Pattern);
+
+ // #include_next <header>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("include_next");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddTextChunk("<");
+ Pattern->AddPlaceholderChunk("header");
+ Pattern->AddTextChunk(">");
+ Results.AddResult(Pattern);
+
+ // #warning <message>
+ Pattern = new CodeCompletionString;
+ Pattern->AddTypedTextChunk("warning");
+ Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Pattern->AddPlaceholderChunk("message");
+ Results.AddResult(Pattern);
+
+ // Note: #ident and #sccs are such crazy anachronisms that we don't provide
+ // completions for them. And __include_macros is a Clang-internal extension
+ // that we don't want to encourage anyone to use.
+
+ // FIXME: we don't support #assert or #unassert, so don't suggest them.
+ Results.ExitScope();
+
+ // FIXME: Create a new code-completion context for this?
+ HandleCodeCompleteResults(this, CodeCompleter,
+ CodeCompletionContext::CCC_Other,
+ Results.data(), Results.size());
+}
+
+void Sema::CodeCompleteInPreprocessorConditionalExclusion(Scope *S) {
+ CodeCompleteOrdinaryName(S, Action::PCC_RecoveryInFunction);
+}
+
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
new file mode 100644
index 0000000..b951c16
--- /dev/null
+++ b/test/Index/complete-preprocessor.m
@@ -0,0 +1,47 @@
+// The line and column layout of this test is significant. Run lines
+// are at the end.
+
+#if 1
+#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)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro}{LeftParen (}{Placeholder args}{RightParen )} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText error}{HorizontalSpace }{Placeholder message} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText if}{HorizontalSpace }{Placeholder condition} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText ifdef}{HorizontalSpace }{Placeholder macro} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText ifndef}{HorizontalSpace }{Placeholder macro} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText import}{HorizontalSpace }{Text "}{Placeholder header}{Text "} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText import}{HorizontalSpace }{Text <}{Placeholder header}{Text >} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText include}{HorizontalSpace }{Text "}{Placeholder header}{Text "} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText include}{HorizontalSpace }{Text <}{Placeholder header}{Text >} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText include_next}{HorizontalSpace }{Text "}{Placeholder header}{Text "} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText include_next}{HorizontalSpace }{Text <}{Placeholder header}{Text >} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText line}{HorizontalSpace }{Placeholder number} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText line}{HorizontalSpace }{Placeholder number}{HorizontalSpace }{Text "}{Placeholder filename}{Text "} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText pragma}{HorizontalSpace }{Placeholder arguments} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText undef}{HorizontalSpace }{Placeholder macro} (30)
+// CHECK-CC1-NEXT: NotImplemented:{TypedText warning}{HorizontalSpace }{Placeholder message} (30)
+// RUN: c-index-test -code-completion-at=%s:5:2 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro}{LeftParen (}{Placeholder args}{RightParen )} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText elif}{HorizontalSpace }{Placeholder condition} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText else} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText endif} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText error}{HorizontalSpace }{Placeholder message} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText if}{HorizontalSpace }{Placeholder condition} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText ifdef}{HorizontalSpace }{Placeholder macro} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText ifndef}{HorizontalSpace }{Placeholder macro} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText import}{HorizontalSpace }{Text "}{Placeholder header}{Text "} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText import}{HorizontalSpace }{Text <}{Placeholder header}{Text >} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText include}{HorizontalSpace }{Text "}{Placeholder header}{Text "} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText include}{HorizontalSpace }{Text <}{Placeholder header}{Text >} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText include_next}{HorizontalSpace }{Text "}{Placeholder header}{Text "} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText include_next}{HorizontalSpace }{Text <}{Placeholder header}{Text >} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText line}{HorizontalSpace }{Placeholder number} (30)
+// CHECK-CC2-NEXT: NotImplemented:{TypedText line}{HorizontalSpace }{Placeholder number}{HorizontalSpace }{Text "}{Placeholder filename}{Text "} (30)
+// 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)