arphaman updated this revision to Diff 95297.
arphaman added a comment.

I've decided to treat each placeholder as an identifier token (like Swift) 
instead of just lexing the contents. This will prevent spurious errors for 
declaration name placeholders that have spaces or hyphens inside.


Repository:
  rL LLVM

https://reviews.llvm.org/D32081

Files:
  include/clang/Basic/Diagnostic.h
  include/clang/Basic/DiagnosticLexKinds.td
  include/clang/Basic/DiagnosticOptions.def
  include/clang/Driver/Options.td
  include/clang/Lex/Lexer.h
  lib/Basic/Diagnostic.cpp
  lib/Basic/DiagnosticIDs.cpp
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Lex/Lexer.cpp
  test/Driver/clang_f_opts.c
  test/Lexer/editor-placeholder.cpp
  test/Parser/placeholder-recovery.m

Index: test/Parser/placeholder-recovery.m
===================================================================
--- test/Parser/placeholder-recovery.m
+++ test/Parser/placeholder-recovery.m
@@ -1,11 +1,14 @@
 // 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'}}
Index: test/Lexer/editor-placeholder.cpp
===================================================================
--- /dev/null
+++ test/Lexer/editor-placeholder.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only  -fsuppress-editor-placeholder-error -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
+};
+
+void avoidPlaceholderErrors(Struct &obj) {
+    while (<#condition#>) {
+        <#statements#>
+    }
+    obj.method(<#Struct &x#>);
+#ifndef SUPPRESS
+  // expected-error@-5 {{editor placeholder in source file}}
+  // expected-error@-5 {{editor placeholder in source file}}
+  // expected-error@-4 {{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'}}
+#ifndef SUPPRESS
+  // expected-error@-2 {{editor placeholder in source file}}
+#endif
+}
Index: test/Driver/clang_f_opts.c
===================================================================
--- test/Driver/clang_f_opts.c
+++ test/Driver/clang_f_opts.c
@@ -494,3 +494,8 @@
 // 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 -fsuppress-editor-placeholder-error %s 2>&1 | FileCheck -check-prefix=CHECK-SUPPRESS-PLACEHOLDER-ERROR %s
+// RUN: %clang -### -S -fno-suppress-editor-placeholder-error %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SUPPRESS-PLACEHOLDER-ERROR %s
+// CHECK-SUPPRESS-PLACEHOLDER-ERROR: -fsuppress-editor-placeholder-error
+// CHECK-NO-SUPPRESS-PLACEHOLDER-ERROR-NOT: -fsuppress-editor-placeholder-error
Index: lib/Lex/Lexer.cpp
===================================================================
--- lib/Lex/Lexer.cpp
+++ lib/Lex/Lexer.cpp
@@ -2722,6 +2722,43 @@
   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 (!PP->getDiagnostics()
+           .getDiagnosticOptions()
+           .SuppressEditorPlaceholderError)
+    Diag(Start, diag::err_placeholder_in_source);
+  // Suppress the diagnostics in range of the editor placeholder.
+  PP->getDiagnostics().suppressDiagnosticsInRange(
+      SourceRange(FileLoc.getLocWithOffset(Start - BufferStart),
+                  FileLoc.getLocWithOffset(End - BufferStart)));
+
+  Result.startToken();
+  FormTokenWithChars(Result, End, tok::raw_identifier);
+  Result.setRawIdentifierData(Start);
+  PP->LookUpIdentifierInfo(Result);
+  BufferPtr = End;
+  return true;
+}
+
 bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
   if (PP && PP->isCodeCompletionEnabled()) {
     SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
@@ -3479,6 +3516,8 @@
     } 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;
     }
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1092,6 +1092,8 @@
       << Opts.TabStop << DiagnosticOptions::DefaultTabStop;
   }
   Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags);
+  Opts.SuppressEditorPlaceholderError =
+      Args.hasArg(OPT_fsuppress_editor_placeholder_error);
   addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings);
   addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks);
 
Index: lib/Driver/ToolChains/Clang.cpp
===================================================================
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -2290,6 +2290,9 @@
   if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
                     true))
     CmdArgs.push_back("-fno-strict-return");
+  if (Args.hasFlag(options::OPT_fsuppress_editor_placeholder_error,
+                   options::OPT_fno_suppress_editor_placeholder_error, false))
+    CmdArgs.push_back("-fsuppress-editor-placeholder-error");
   if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
                    options::OPT_fno_strict_vtable_pointers,
                    false))
Index: lib/Basic/DiagnosticIDs.cpp
===================================================================
--- lib/Basic/DiagnosticIDs.cpp
+++ lib/Basic/DiagnosticIDs.cpp
@@ -477,6 +477,18 @@
           Diag.getSourceManager().getExpansionLoc(Loc)))
     return diag::Severity::Ignored;
 
+  // Check if the diagnostic is in a suppressed range.
+  if (Loc.isValid() && Diag.hasSourceManager()) {
+    const SourceManager &SM = Diag.getSourceManager();
+    for (const SourceRange &R : Diag.getSuppressionRanges()) {
+      if (Loc == R.getBegin() || Loc == R.getEnd())
+        return diag::Severity::Ignored;
+      if (SM.isBeforeInTranslationUnit(R.getBegin(), Loc) &&
+          SM.isBeforeInTranslationUnit(Loc, R.getEnd()))
+        return diag::Severity::Ignored;
+    }
+  }
+
   return Result;
 }
 
Index: lib/Basic/Diagnostic.cpp
===================================================================
--- lib/Basic/Diagnostic.cpp
+++ lib/Basic/Diagnostic.cpp
@@ -374,6 +374,10 @@
       setSeverity(Diag, Map, Loc);
 }
 
+void DiagnosticsEngine::suppressDiagnosticsInRange(SourceRange R) {
+  SuppressionRanges.push_back(R);
+}
+
 void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
   assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
 
Index: include/clang/Lex/Lexer.h
===================================================================
--- include/clang/Lex/Lexer.h
+++ include/clang/Lex/Lexer.h
@@ -638,6 +638,8 @@
   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; }
 
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1470,6 +1470,12 @@
 def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>,
   Flags<[CC1Option]>;
 
+def fsuppress_editor_placeholder_error : Flag<["-"], "fsuppress-editor-placeholder-error">, Group<f_Group>,
+  Flags<[CC1Option]>,
+  HelpText<"Suppress the 'editor placeholder in source file' errors">;
+def fno_suppress_editor_placeholder_error : Flag<["-"], "fno-suppress-editor-placeholder-error">, Group<f_Group>,
+  Flags<[CC1Option]>;
+
 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>,
Index: include/clang/Basic/DiagnosticOptions.def
===================================================================
--- include/clang/Basic/DiagnosticOptions.def
+++ include/clang/Basic/DiagnosticOptions.def
@@ -92,6 +92,9 @@
 /// Column limit for formatting message diagnostics, or 0 if unused.
 VALUE_DIAGOPT(MessageLength, 32, 0)
 
+/// True when the 'editor placeholder in source file' has to be supressed.
+DIAGOPT(SuppressEditorPlaceholderError, 1, 0)
+
 #undef DIAGOPT
 #undef ENUM_DIAGOPT
 #undef VALUE_DIAGOPT
Index: include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- include/clang/Basic/DiagnosticLexKinds.td
+++ include/clang/Basic/DiagnosticLexKinds.td
@@ -242,6 +242,7 @@
   "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">;
 
 
 //===----------------------------------------------------------------------===//
Index: include/clang/Basic/Diagnostic.h
===================================================================
--- include/clang/Basic/Diagnostic.h
+++ include/clang/Basic/Diagnostic.h
@@ -390,6 +390,9 @@
   /// and '='.
   std::string FlagValue;
 
+  /// The source ranges in which all diagnostics should be supressed.
+  std::vector<SourceRange> SuppressionRanges;
+
 public:
   explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
                              DiagnosticOptions *DiagOpts,
@@ -688,7 +691,15 @@
   /// \brief Reset the state of the diagnostic object to its initial 
   /// configuration.
   void Reset();
-  
+
+  /// Specify a new source range in which all of the diagnostics will be
+  /// supressed.
+  void suppressDiagnosticsInRange(SourceRange R);
+
+  ArrayRef<SourceRange> getSuppressionRanges() const {
+    return SuppressionRanges;
+  }
+
   //===--------------------------------------------------------------------===//
   // DiagnosticsEngine classification and reporting interfaces.
   //
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to