[clang] c23ee77 - [www] List both the regular and expanded form of %diff in the

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Mar 30 17:25:29 PDT 2021


Author: Richard Smith
Date: 2021-03-30T17:25:01-07:00
New Revision: c23ee7718ea4f9292622af3d80efe2491eb2a506

URL: https://github.com/llvm/llvm-project/commit/c23ee7718ea4f9292622af3d80efe2491eb2a506
DIFF: https://github.com/llvm/llvm-project/commit/c23ee7718ea4f9292622af3d80efe2491eb2a506.diff

LOG: [www] List both the regular and expanded form of %diff in the
diagnostics reference.

In passing, properly validate and diagnose errors in %diff format
specifiers.

Added: 
    

Modified: 
    clang/utils/TableGen/ClangDiagnosticsEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 77c4786723247..014c1adcd8092 100644
--- a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -557,7 +557,7 @@ struct PluralPiece : SelectPiece {
 struct DiffPiece : Piece {
   DiffPiece() : Piece(DiffPieceClass) {}
 
-  Piece *Options[2] = {};
+  Piece *Parts[4] = {};
   int Indexes[2] = {};
 
   static bool classof(const Piece *P) {
@@ -633,9 +633,18 @@ struct DiagnosticTextBuilder {
     }
 
     DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
-        : Builder(Builder), Root(parseDiagText(Text)) {}
-
-    Piece *parseDiagText(StringRef &Text, bool Nested = false);
+        : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {}
+
+    enum class StopAt {
+      // Parse until the end of the string.
+      End,
+      // Additionally stop if we hit a non-nested '|' or '}'.
+      PipeOrCloseBrace,
+      // Additionally stop if we hit a non-nested '$'.
+      Dollar,
+    };
+
+    Piece *parseDiagText(StringRef &Text, StopAt Stop);
     int parseModifier(StringRef &) const;
 
   public:
@@ -901,7 +910,24 @@ struct DiagTextDocPrinter : DiagTextVisitor<DiagTextDocPrinter> {
 
   void VisitPlural(PluralPiece *P) { VisitSelect(P); }
 
-  void VisitDiff(DiffPiece *P) { Visit(P->Options[1]); }
+  void VisitDiff(DiffPiece *P) {
+    // Render %
diff {a $ b $ c|d}e,f as %select{a %e b %f c|d}.
+    PlaceholderPiece E(MT_Placeholder, P->Indexes[0]);
+    PlaceholderPiece F(MT_Placeholder, P->Indexes[1]);
+
+    MultiPiece FirstOption;
+    FirstOption.Pieces.push_back(P->Parts[0]);
+    FirstOption.Pieces.push_back(&E);
+    FirstOption.Pieces.push_back(P->Parts[1]);
+    FirstOption.Pieces.push_back(&F);
+    FirstOption.Pieces.push_back(P->Parts[2]);
+
+    SelectPiece Select(MT_Diff);
+    Select.Options.push_back(&FirstOption);
+    Select.Options.push_back(P->Parts[3]);
+
+    VisitSelect(&Select);
+  }
 
   std::vector<std::string> &RST;
 };
@@ -955,9 +981,13 @@ struct DiagTextPrinter : DiagTextVisitor<DiagTextPrinter> {
 
   void VisitDiff(DiffPiece *P) {
     Result += "%
diff {";
-    Visit(P->Options[0]);
+    Visit(P->Parts[0]);
+    Result += "$";
+    Visit(P->Parts[1]);
+    Result += "$";
+    Visit(P->Parts[2]);
     Result += "|";
-    Visit(P->Options[1]);
+    Visit(P->Parts[3]);
     Result += "}";
     addInt(mapIndex(P->Indexes[0]));
     Result += ",";
@@ -982,16 +1012,19 @@ int DiagnosticTextBuilder::DiagText::parseModifier(StringRef &Text) const {
 }
 
 Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
-                                                      bool Nested) {
+                                                      StopAt Stop) {
   std::vector<Piece *> Parsed;
 
+  constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"};
+  llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)];
+
   while (!Text.empty()) {
     size_t End = (size_t)-2;
     do
-      End = Nested ? Text.find_first_of("%|}", End + 2)
-                   : Text.find_first_of('%', End + 2);
-    while (End < Text.size() - 1 && Text[End] == '%' &&
-           (Text[End + 1] == '%' || Text[End + 1] == '|'));
+      End = Text.find_first_of(StopSet, End + 2);
+    while (
+        End < Text.size() - 1 && Text[End] == '%' &&
+        (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$'));
 
     if (End) {
       Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
@@ -1000,7 +1033,7 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
         break;
     }
 
-    if (Text[0] == '|' || Text[0] == '}')
+    if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$')
       break;
 
     // Drop the '%'.
@@ -1023,6 +1056,12 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
                                .Case("", MT_Placeholder)
                                .Default(MT_Unknown);
 
+    auto ExpectAndConsume = [&](StringRef Prefix) {
+      if (!Text.consume_front(Prefix))
+        Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" +
+                                Modifier);
+    };
+
     switch (ModType) {
     case MT_Unknown:
       Builder.PrintFatalError("Unknown modifier type: " + Modifier);
@@ -1030,11 +1069,11 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
       SelectPiece *Select = New<SelectPiece>(MT_Select);
       do {
         Text = Text.drop_front(); // '{' or '|'
-        Select->Options.push_back(parseDiagText(Text, true));
+        Select->Options.push_back(
+            parseDiagText(Text, StopAt::PipeOrCloseBrace));
         assert(!Text.empty() && "malformed %select");
       } while (Text.front() == '|');
-      // Drop the trailing '}'.
-      Text = Text.drop_front(1);
+      ExpectAndConsume("}");
       Select->Index = parseModifier(Text);
       Parsed.push_back(Select);
       continue;
@@ -1051,24 +1090,24 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
         Plural->OptionPrefixes.push_back(
             New<TextPiece>(Text.slice(0, End), "diagtext"));
         Text = Text.slice(End, StringRef::npos);
-        Plural->Options.push_back(parseDiagText(Text, true));
-        assert(!Text.empty() && "malformed %select");
+        Plural->Options.push_back(
+            parseDiagText(Text, StopAt::PipeOrCloseBrace));
+        assert(!Text.empty() && "malformed %plural");
       } while (Text.front() == '|');
-      // Drop the trailing '}'.
-      Text = Text.drop_front(1);
+      ExpectAndConsume("}");
       Plural->Index = parseModifier(Text);
       Parsed.push_back(Plural);
       continue;
     }
     case MT_Sub: {
       SubstitutionPiece *Sub = New<SubstitutionPiece>();
-      Text = Text.drop_front(); // '{'
+      ExpectAndConsume("{");
       size_t NameSize = Text.find_first_of('}');
       assert(NameSize != size_t(-1) && "failed to find the end of the name");
       assert(NameSize != 0 && "empty name?");
       Sub->Name = Text.substr(0, NameSize).str();
       Text = Text.drop_front(NameSize);
-      Text = Text.drop_front(); // '}'
+      ExpectAndConsume("}");
       if (!Text.empty()) {
         while (true) {
           if (!isdigit(Text[0]))
@@ -1086,14 +1125,17 @@ Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
     }
     case MT_Diff: {
       DiffPiece *Diff = New<DiffPiece>();
-      Text = Text.drop_front(); // '{'
-      Diff->Options[0] = parseDiagText(Text, true);
-      Text = Text.drop_front(); // '|'
-      Diff->Options[1] = parseDiagText(Text, true);
-
-      Text = Text.drop_front(); // '}'
+      ExpectAndConsume("{");
+      Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar);
+      ExpectAndConsume("$");
+      Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar);
+      ExpectAndConsume("$");
+      Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
+      ExpectAndConsume("|");
+      Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
+      ExpectAndConsume("}");
       Diff->Indexes[0] = parseModifier(Text);
-      Text = Text.drop_front(); // ','
+      ExpectAndConsume(",");
       Diff->Indexes[1] = parseModifier(Text);
       Parsed.push_back(Diff);
       continue;


        


More information about the cfe-commits mailing list