"illegal character encoding in character literal">,
InGroup<InvalidSourceEncoding>;
def err_lexing_string : Error<"failure when lexing a string">;
+def err_placeholder_in_source : Error<"editor placeholder in source file">;
//===----------------------------------------------------------------------===//
RecomputeNeedsHandleIdentifier();
}
+ /// Return true if this identifier is an editor placeholder.
+ ///
+ /// Editor placeholders are produced by the code-completion engine and are
+ /// represented as characters between '<#' and '#>' in the source code. An
+ /// example of auto-completed call with a placeholder parameter is shown
+ /// below:
+ /// \code
+ /// function(<#int x#>);
+ /// \endcode
+ bool isEditorPlaceholder() const {
+ return getName().startswith("<#") && getName().endswith("#>");
+ }
+
/// \brief Provide less than operator for lexicographical sorting.
bool operator<(const IdentifierInfo &RHS) const {
return getName() < RHS.getName();
LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation")
+LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source")
+
#undef LANGOPT
#undef COMPATIBLE_LANGOPT
#undef BENIGN_LANGOPT
def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>,
Flags<[CC1Option]>;
+def fallow_editor_placeholders : Flag<["-"], "fallow-editor-placeholders">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Treat editor placeholders as valid source code">;
+def fno_allow_editor_placeholders : Flag<["-"],
+ "fno-allow-editor-placeholders">, Group<f_Group>;
+
def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">;
def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>,
bool IsStartOfConflictMarker(const char *CurPtr);
bool HandleEndOfConflictMarker(const char *CurPtr);
+ bool lexEditorPlaceholder(Token &Result, const char *CurPtr);
+
bool isCodeCompletionPoint(const char *CurPtr) const;
void cutOffLexing() { BufferPtr = BufferEnd; }
StringifiedInMacro = 0x100, // This string or character literal is formed by
// macro stringizing or charizing operator.
CommaAfterElided = 0x200, // The comma following this token was elided (MS).
+ IsEditorPlaceholder = 0x400, // This identifier is a placeholder.
};
tok::TokenKind getKind() const { return Kind; }
/// Returns true if the comma after this token was elided.
bool commaAfterElided() const { return getFlag(CommaAfterElided); }
+
+ /// Returns true if this token is an editor placeholder.
+ ///
+ /// Editor placeholders are produced by the code-completion engine and are
+ /// represented as characters between '<#' and '#>' in the source code. The
+ /// lexer uses identifier tokens to represent placeholders.
+ bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
};
/// \brief Information about the conditional stack (\#if directives)
if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
true))
CmdArgs.push_back("-fno-strict-return");
+ if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
+ options::OPT_fno_allow_editor_placeholders, false))
+ CmdArgs.push_back("-fallow-editor-placeholders");
if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
options::OPT_fno_strict_vtable_pointers,
false))
Args.getAllArgValues(OPT_fxray_always_instrument);
Opts.XRayNeverInstrumentFiles =
Args.getAllArgValues(OPT_fxray_never_instrument);
+
+ // -fallow-editor-placeholders
+ Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
}
static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
return false;
}
+static const char *findPlaceholderEnd(const char *CurPtr,
+ const char *BufferEnd) {
+ if (CurPtr == BufferEnd)
+ return nullptr;
+ BufferEnd -= 1; // Scan until the second last character.
+ for (; CurPtr != BufferEnd; ++CurPtr) {
+ if (CurPtr[0] == '#' && CurPtr[1] == '>')
+ return CurPtr + 2;
+ }
+ return nullptr;
+}
+
+bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) {
+ assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!");
+ if (!PP || LexingRawMode)
+ return false;
+ const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd);
+ if (!End)
+ return false;
+ const char *Start = CurPtr - 1;
+ if (!LangOpts.AllowEditorPlaceholders)
+ Diag(Start, diag::err_placeholder_in_source);
+ Result.startToken();
+ FormTokenWithChars(Result, End, tok::raw_identifier);
+ Result.setRawIdentifierData(Start);
+ PP->LookUpIdentifierInfo(Result);
+ Result.setFlag(Token::IsEditorPlaceholder);
+ BufferPtr = End;
+ return true;
+}
+
bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
if (PP && PP->isCodeCompletionEnabled()) {
SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
} else if (LangOpts.Digraphs && Char == '%') { // '<%' -> '{'
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_brace;
+ } else if (Char == '#' && lexEditorPlaceholder(Result, CurPtr)) {
+ return true;
} else {
Kind = tok::less;
}
default:
dont_know:
+ if (Tok.isEditorPlaceholder()) {
+ ConsumeToken();
+ return nullptr;
+ }
// We can't tell whether this is a function-definition or declaration yet.
return ParseDeclarationOrFunctionDefinition(attrs, DS);
}
return false;
}
}
+ if (Tok.isEditorPlaceholder())
+ return true;
Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
return true;
bool ErrorRecoveryLookup,
bool *IsCorrectedToColon,
bool OnlyNamespace) {
+ if (IdInfo.Identifier->isEditorPlaceholder())
+ return true;
LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
OnlyNamespace ? LookupNamespaceName
: LookupNestedNameSpecifierName);
CXXScopeSpec *SS,
ParsedType &SuggestedType,
bool AllowClassTemplates) {
+ // Don't report typename errors for editor placeholders.
+ if (II->isEditorPlaceholder())
+ return;
// We don't have anything to suggest (yet).
SuggestedType = nullptr;
IdentifierInfo *II = Name.getAsIdentifierInfo();
SourceLocation NameLoc = NameInfo.getLoc();
+ if (II && II->isEditorPlaceholder()) {
+ // FIXME: When typed placeholders are supported we can create a typed
+ // placeholder expression node.
+ return ExprError();
+ }
+
// C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
// -- an identifier that was declared with a dependent type,
// RUN: %clang -### -S -fdebug-info-for-profiling -fno-debug-info-for-profiling %s 2>&1 | FileCheck -check-prefix=CHECK-NO-PROFILE-DEBUG %s
// CHECK-PROFILE-DEBUG: -fdebug-info-for-profiling
// CHECK-NO-PROFILE-DEBUG-NOT: -fdebug-info-for-profiling
+
+// RUN: %clang -### -S -fallow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-ALLOW-PLACEHOLDERS %s
+// RUN: %clang -### -S -fno-allow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-NO-ALLOW-PLACEHOLDERS %s
+// CHECK-ALLOW-PLACEHOLDERS: -fallow-editor-placeholders
+// CHECK-NO-ALLOW-PLACEHOLDERS-NOT: -fallow-editor-placeholders
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fallow-editor-placeholders -DSUPPRESS -verify %s
+
+struct Struct {
+public:
+ void method(Struct &x);
+};
+
+struct <#struct name#> {
+ int <#field-name#>;
+#ifndef SUPPRESS
+ // expected-error@-3 {{editor placeholder in source file}}
+ // expected-error@-3 {{editor placeholder in source file}}
+#endif
+};
+
+typename <#typename#>::<#name#>;
+decltype(<#expression#>) foobar;
+typedef <#type#> <#name#>;
+#ifndef SUPPRESS
+ // expected-error@-4 2 {{editor placeholder in source file}}
+ // expected-error@-4 {{editor placeholder in source file}}
+ // expected-error@-4 2 {{editor placeholder in source file}}
+#endif
+
+namespace <#identifier#> {
+ <#declarations#>
+#ifndef SUPPRESS
+ // expected-error@-3 {{editor placeholder in source file}}
+ // expected-error@-3 {{editor placeholder in source file}}
+#endif
+
+}
+
+using <#qualifier#>::<#name#>;
+#ifndef SUPPRESS
+ // expected-error@-2 2 {{editor placeholder in source file}}
+#endif
+
+void avoidPlaceholderErrors(Struct &obj) {
+ static_cast< <#type#> >(<#expression#>);
+ while (<#condition#>) {
+ <#statements#>
+ }
+ obj.method(<#Struct &x#>);
+#ifndef SUPPRESS
+ // expected-error@-6 2 {{editor placeholder in source file}}
+ // expected-error@-6 {{editor placeholder in source file}}
+ // expected-error@-6 {{editor placeholder in source file}}
+ // expected-error@-5 {{editor placeholder in source file}}
+#endif
+ switch (<#expression#>) {
+ case <#constant#>:
+ <#statements#>
+#ifndef SUPPRESS
+ // expected-error@-4 {{editor placeholder in source file}}
+ // expected-error@-4 {{editor placeholder in source file}}
+ // expected-error@-4 {{editor placeholder in source file}}
+#endif
+ break;
+
+ default:
+ break;
+ }
+}
+
+void Struct::method(<#Struct &x#>, noSupressionHere) { // expected-error {{unknown type name 'noSupressionHere'}} expected-error {{C++ requires a type specifier for all declarations}}
+#ifndef SUPPRESS
+ // expected-error@-2 {{editor placeholder in source file}}
+#endif
+}
// RUN: %clang_cc1 -fsyntax-only -verify %s
+@protocol NSObject
+@end
+
+@protocol <#protocol name#> <NSObject> // expected-error {{editor placeholder in source file}}
+// expected-note@-1 {{protocol started here}}
+
// FIXME: We could do much better with this, if we recognized
// placeholders somehow. However, we're content with not generating
// bogus 'archaic' warnings with bad location info.
-@protocol <#protocol name#> <NSObject> // expected-error {{expected identifier or '('}} \
-// expected-error 2{{expected identifier}} \
-// expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
-<#methods#>
+<#methods#> // expected-error {{editor placeholder in source file}}
-@end
+@end // expected-error {{prefix attribute must be followed by an interface or protocol}} expected-error {{missing '@end'}}