From f44e854ed1e3aa86d2ed6d615ccd109d50ddcff9 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 24 Aug 2010 19:08:16 +0000 Subject: [PATCH] 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 --- include/clang/Lex/CodeCompletionHandler.h | 42 +++++ include/clang/Lex/Preprocessor.h | 14 ++ include/clang/Parse/Parser.h | 8 +- include/clang/Sema/Action.h | 10 ++ include/clang/Sema/Sema.h | 2 + lib/Lex/Lexer.cpp | 36 ++--- lib/Lex/PPDirectives.cpp | 13 +- lib/Lex/Preprocessor.cpp | 9 +- lib/Parse/Parser.cpp | 13 ++ lib/Sema/SemaCodeComplete.cpp | 180 ++++++++++++++++++++++ test/Index/complete-preprocessor.m | 47 ++++++ 11 files changed, 351 insertions(+), 23 deletions(-) create mode 100644 include/clang/Lex/CodeCompletionHandler.h create mode 100644 test/Index/complete-preprocessor.m diff --git a/include/clang/Lex/CodeCompletionHandler.h b/include/clang/Lex/CodeCompletionHandler.h new file mode 100644 index 0000000000..4cc3b12d47 --- /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 8bf0df3d02..712feaa425 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -42,6 +42,7 @@ class CommentHandler; class ScratchBuffer; class TargetInfo; class PPCallbacks; +class CodeCompletionHandler; class DirectoryLookup; class PreprocessingRecord; @@ -131,6 +132,9 @@ class Preprocessor { /// with this preprocessor. std::vector 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 @@ public: /// 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 ceaeb34ee5..83b42fd172 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 @@ namespace prec { /// 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 @@ private: //===--------------------------------------------------------------------===// // 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 1d3d460b41..d407037515 100644 --- a/include/clang/Sema/Action.h +++ b/include/clang/Sema/Action.h @@ -3205,6 +3205,16 @@ public: 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 3991bce7e1..b4449ff45c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4690,6 +4690,8 @@ public: ParsedType ReturnType, IdentifierInfo **SelIdents, unsigned NumSelIdents); + virtual void CodeCompletePreprocessorDirective(Scope *S, bool InConditional); + virtual void CodeCompleteInPreprocessorConditionalExclusion(Scope *S); void GatherGlobalCodeCompletions( llvm::SmallVectorImpl &Results); //@} diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 9a96934d49..3a77bbbfba 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -1523,6 +1523,22 @@ std::string Lexer::ReadToEndOfLine() { /// 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 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { 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 e000c54768..e0729f123f 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 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, 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 @@ TryAgain: // 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 d3959aa706..04de68baef 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 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, 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 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { CommentHandler::~CommentHandler() { } +CodeCompletionHandler::~CodeCompletionHandler() { } + void Preprocessor::createPreprocessingRecord() { if (Record) return; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 8fd1e48994..230506d85f 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -50,6 +50,8 @@ Parser::Parser(Preprocessor &pp, Action &actions) 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 @@ Parser::~Parser() { UnusedHandler.reset(); PP.RemovePragmaHandler(WeakHandler.get()); WeakHandler.reset(); + PP.clearCodeCompletionHandler(); } /// Initialize - Warm up the parser. @@ -1126,3 +1129,13 @@ void Parser::CodeCompletionRecovery() { // 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 082ebcfd15..14043e8b62 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4607,6 +4607,186 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, Results.data(),Results.size()); } +void Sema::CodeCompletePreprocessorDirective(Scope *S, bool InConditional) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // #if + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("if"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("condition"); + Results.AddResult(Pattern); + + // #ifdef + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("ifdef"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Results.AddResult(Pattern); + + // #ifndef + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("ifndef"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Results.AddResult(Pattern); + + if (InConditional) { + // #elif + 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
+ Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("include"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("<"); + Pattern->AddPlaceholderChunk("header"); + Pattern->AddTextChunk(">"); + Results.AddResult(Pattern); + + // #define + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("define"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Results.AddResult(Pattern); + + // #define () + 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 + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("undef"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Results.AddResult(Pattern); + + // #line + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("line"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("number"); + Results.AddResult(Pattern); + + // #line "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 + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("error"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("message"); + Results.AddResult(Pattern); + + // #pragma + 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
+ 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
+ Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("include_next"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("<"); + Pattern->AddPlaceholderChunk("header"); + Pattern->AddTextChunk(">"); + Results.AddResult(Pattern); + + // #warning + 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 &Results) { ResultBuilder Builder(*this); diff --git a/test/Index/complete-preprocessor.m b/test/Index/complete-preprocessor.m new file mode 100644 index 0000000000..b951c1622e --- /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) -- 2.40.0