The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
5.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. #pragma once
  14. //==============================================================================
  15. struct DiagnosticMessage
  16. {
  17. DiagnosticMessage() = default;
  18. DiagnosticMessage (const DiagnosticMessage& other)
  19. : associatedDiagnostic (createCopyIfNotNull (other.associatedDiagnostic.get())),
  20. message (other.message),
  21. mainFile (other.mainFile),
  22. range (other.range),
  23. type (other.type)
  24. {
  25. }
  26. DiagnosticMessage& operator= (const DiagnosticMessage& other)
  27. {
  28. associatedDiagnostic.reset (createCopyIfNotNull (other.associatedDiagnostic.get()));
  29. message = other.message;
  30. mainFile = other.mainFile;
  31. range = other.range;
  32. type = other.type;
  33. return *this;
  34. }
  35. enum Type
  36. {
  37. error = 0,
  38. warning = 1,
  39. note = 2
  40. };
  41. std::unique_ptr<DiagnosticMessage> associatedDiagnostic;
  42. String message;
  43. String mainFile;
  44. SourceCodeRange range;
  45. Type type;
  46. bool isError() const noexcept { return type == error; }
  47. bool isWarning() const noexcept { return type == warning; }
  48. bool isNote() const noexcept { return type == note; }
  49. String toString() const
  50. {
  51. // todo: copy recursively from root
  52. String res;
  53. switch (type)
  54. {
  55. case error: res << "error: "; break;
  56. case warning: res << "warning: "; break;
  57. case note: res << "note: "; break;
  58. default: break;
  59. };
  60. res << mainFile << ": ";
  61. res << message << "\n";
  62. return res;
  63. }
  64. ValueTree toValueTree() const
  65. {
  66. ValueTree v (MessageTypes::DIAGNOSTIC);
  67. v.setProperty (Ids::text, message, nullptr);
  68. v.setProperty (Ids::file, mainFile, nullptr);
  69. v.setProperty (Ids::range, range.toString(), nullptr);
  70. v.setProperty (Ids::type, (int) type, nullptr);
  71. if (associatedDiagnostic != nullptr)
  72. v.addChild (associatedDiagnostic->toValueTree(), 0, nullptr);
  73. return v;
  74. }
  75. static DiagnosticMessage fromValueTree (const ValueTree& v)
  76. {
  77. DiagnosticMessage d;
  78. d.message = v[Ids::text];
  79. d.mainFile = v[Ids::file];
  80. d.range = SourceCodeRange (v [Ids::range]);
  81. d.type = (Type) static_cast<int> (v[Ids::type]);
  82. auto associated = v.getChild (0);
  83. if (associated.isValid())
  84. d.associatedDiagnostic.reset (new DiagnosticMessage (fromValueTree (associated)));
  85. return d;
  86. }
  87. bool operator== (const DiagnosticMessage& other) const noexcept
  88. {
  89. return range == other.range
  90. && message == other.message
  91. && mainFile == other.mainFile;
  92. }
  93. bool operator!= (const DiagnosticMessage& other) const noexcept { return ! operator== (other); }
  94. };
  95. //==============================================================================
  96. struct DiagnosticList
  97. {
  98. // after some research, it seems that notes never come on their own
  99. // i.e. they always have a warning / error preceding them
  100. // so we can keep notes and their associated diagnostics
  101. // together by keeping track of the last message
  102. DiagnosticMessage lastMessage;
  103. ValueTree list { MessageTypes::DIAGNOSTIC_LIST };
  104. void clear()
  105. {
  106. list = ValueTree { MessageTypes::DIAGNOSTIC_LIST };
  107. lastMessage = DiagnosticMessage();
  108. }
  109. void add (DiagnosticMessage m)
  110. {
  111. if (m.isNote())
  112. {
  113. if (lastMessage.message.isEmpty())
  114. return; // seems to happen sometimes, but with seemingly duplicated messages (?)
  115. m.associatedDiagnostic.reset (new DiagnosticMessage (lastMessage));
  116. }
  117. else
  118. {
  119. lastMessage = m;
  120. }
  121. list.appendChild (m.toValueTree(), nullptr);
  122. }
  123. void add (const DiagnosticList& l)
  124. {
  125. jassert (l.list != list);
  126. for (int i = 0; i < l.list.getNumChildren(); ++i)
  127. list.appendChild (l.list.getChild(i).createCopy(), nullptr);
  128. }
  129. void remove (DiagnosticMessage m)
  130. {
  131. auto n = m.toValueTree();
  132. for (int i = 0; i < list.getNumChildren(); ++i)
  133. {
  134. if (list.getChild (i).isEquivalentTo (n))
  135. {
  136. list.removeChild (i, nullptr);
  137. return;
  138. }
  139. }
  140. jassertfalse;
  141. }
  142. bool hasRecoveryWarning (DiagnosticMessage m) const
  143. {
  144. auto n = m.toValueTree();
  145. for (int i = 0; i < list.getNumChildren(); ++i)
  146. if (list.getChild (i).isEquivalentTo (n))
  147. return true;
  148. return false;
  149. }
  150. const ValueTree& toValueTree() const noexcept
  151. {
  152. return list;
  153. }
  154. void loadFromChildOfValueTree (ValueTree& parent)
  155. {
  156. list = parent.getChildWithName (MessageTypes::DIAGNOSTIC_LIST).createCopy();
  157. }
  158. };