|
19 | 19 | #include "swift/Basic/STLExtras.h" |
20 | 20 | #include "llvm/ADT/DenseMap.h" |
21 | 21 | #include "llvm/ADT/SmallSet.h" |
| 22 | +#include "llvm/ADT/STLExtras.h" |
22 | 23 | #include <limits.h> |
23 | 24 | #include <optional> |
24 | 25 | #include <vector> |
@@ -72,15 +73,15 @@ class BracketOptions { |
72 | 73 | CloseExtension(CloseExtension), |
73 | 74 | CloseNominal(CloseNominal) {} |
74 | 75 |
|
75 | | - bool shouldOpenExtension(const Decl *D) { |
| 76 | + bool shouldOpenExtension(const Decl *D) const { |
76 | 77 | return D != Target || OpenExtension; |
77 | 78 | } |
78 | 79 |
|
79 | | - bool shouldCloseExtension(const Decl *D) { |
| 80 | + bool shouldCloseExtension(const Decl *D) const { |
80 | 81 | return D != Target || CloseExtension; |
81 | 82 | } |
82 | 83 |
|
83 | | - bool shouldCloseNominal(const Decl *D) { |
| 84 | + bool shouldCloseNominal(const Decl *D) const { |
84 | 85 | return D != Target || CloseNominal; |
85 | 86 | } |
86 | 87 | }; |
@@ -127,7 +128,39 @@ struct ShouldPrintChecker { |
127 | 128 | /// |
128 | 129 | /// A default-constructed PrintOptions is suitable for printing to users; |
129 | 130 | /// there are also factory methods for specific use cases. |
| 131 | +/// |
| 132 | +/// The value semantics of PrintOptions are a little messed up. We generally |
| 133 | +/// pass around options by const reference in order to (1) make it |
| 134 | +/// easier to pass in temporaries and (2) discourage direct local mutation |
| 135 | +/// in favor of the OverrideScope system below. However, that override |
| 136 | +/// system assumes that PrintOptions objects are always actually mutable. |
130 | 137 | struct PrintOptions { |
| 138 | + |
| 139 | + /// Explicitly copy these print options. You should generally aim to |
| 140 | + /// avoid doing this, especially in deeply-embedded code, because |
| 141 | + /// PrintOptions is a relatively heavyweight type (and is likely to |
| 142 | + /// only get more heavyweight). Instead, try to use OverrideScope. |
| 143 | + PrintOptions clone() const { return *this; } |
| 144 | + |
| 145 | + /// Allow move construction and assignment. We don't expect to |
| 146 | + /// actually use these much, but there isn't too much harm from |
| 147 | + /// them. |
| 148 | + PrintOptions(PrintOptions &&) = default; |
| 149 | + PrintOptions &operator=(PrintOptions &&) = default; |
| 150 | + |
| 151 | +private: |
| 152 | + /// Disallow implicit copying, but make it available privately for the |
| 153 | + /// use of clone(). |
| 154 | + PrintOptions(const PrintOptions &) = default; |
| 155 | + |
| 156 | + /// Disallow copy assignment completely, which we don't even need |
| 157 | + /// privately. |
| 158 | + PrintOptions &operator=(const PrintOptions &) = delete; |
| 159 | + |
| 160 | +public: |
| 161 | + // defined later in this file |
| 162 | + class OverrideScope; |
| 163 | + |
131 | 164 | /// The indentation width. |
132 | 165 | unsigned Indent = 2; |
133 | 166 |
|
@@ -749,6 +782,8 @@ struct PrintOptions { |
749 | 782 | void setBaseType(Type T); |
750 | 783 |
|
751 | 784 | void initForSynthesizedExtension(TypeOrExtensionDecl D); |
| 785 | + void initForSynthesizedExtensionInScope(TypeOrExtensionDecl D, |
| 786 | + OverrideScope &scope) const; |
752 | 787 |
|
753 | 788 | void clearSynthesizedExtension(); |
754 | 789 |
|
@@ -823,7 +858,87 @@ struct PrintOptions { |
823 | 858 | PO.AlwaysTryPrintParameterLabels = true; |
824 | 859 | return PO; |
825 | 860 | } |
| 861 | + |
| 862 | + /// An RAII scope for performing temporary adjustments to a PrintOptions |
| 863 | + /// object. Even with the abstraction inherent in this design, this can |
| 864 | + /// be significantly cheaper than copying the options just to modify a few |
| 865 | + /// fields. |
| 866 | + /// |
| 867 | + /// At its core, this is just a stack of arbitrary functions to run |
| 868 | + /// when the scope is destroyed. |
| 869 | + class OverrideScope { |
| 870 | + public: |
| 871 | + /// The mutable options exposed by the scope. Generally, you should not |
| 872 | + /// access this directly. |
| 873 | + PrintOptions &Options; |
| 874 | + |
| 875 | + private: |
| 876 | + /// A stack of finalizer functions, each of which generally undoes some |
| 877 | + /// change that was made to the options. |
| 878 | + SmallVector<std::function<void(PrintOptions &)>, 4> Finalizers; |
| 879 | + |
| 880 | + public: |
| 881 | + OverrideScope(const PrintOptions &options) |
| 882 | + : Options(const_cast<PrintOptions &>(options)) {} |
| 883 | + |
| 884 | + // Disallow all copies and moves. |
| 885 | + OverrideScope(const OverrideScope &scope) = delete; |
| 886 | + OverrideScope &operator=(const OverrideScope &scope) = delete; |
| 887 | + |
| 888 | + ~OverrideScope() { |
| 889 | + // Run the finalizers in the opposite order that they were added. |
| 890 | + for (auto &finalizer : llvm::reverse(Finalizers)) { |
| 891 | + finalizer(Options); |
| 892 | + } |
| 893 | + } |
| 894 | + |
| 895 | + template <class Fn> |
| 896 | + void addFinalizer(Fn &&fn) { |
| 897 | + Finalizers.emplace_back(std::move(fn)); |
| 898 | + } |
| 899 | + |
| 900 | + void addExcludedAttr(AnyAttrKind kind) { |
| 901 | + Options.ExcludeAttrList.push_back(kind); |
| 902 | + addFinalizer([](PrintOptions &options) { |
| 903 | + options.ExcludeAttrList.pop_back(); |
| 904 | + }); |
| 905 | + } |
| 906 | + }; |
826 | 907 | }; |
827 | | -} |
| 908 | + |
| 909 | +/// Override a print option within an OverrideScope. Does a check to see if |
| 910 | +/// the new value is the same as the old before actually doing anything, so |
| 911 | +/// it only works if the type provides ==. |
| 912 | +/// |
| 913 | +/// Signature is: |
| 914 | +/// void (OverrideScope &scope, <FIELD NAME>, T &&newValue) |
| 915 | +#define OVERRIDE_PRINT_OPTION(SCOPE, FIELD_NAME, VALUE) \ |
| 916 | + do { \ |
| 917 | + auto _newValue = (VALUE); \ |
| 918 | + if ((SCOPE).Options.FIELD_NAME != _newValue) { \ |
| 919 | + auto finalizer = \ |
| 920 | + [_oldValue=(SCOPE).Options.FIELD_NAME](PrintOptions &opts) { \ |
| 921 | + opts.FIELD_NAME = _oldValue; \ |
| 922 | + }; \ |
| 923 | + (SCOPE).Options.FIELD_NAME = std::move(_newValue); \ |
| 924 | + (SCOPE).addFinalizer(std::move(finalizer)); \ |
| 925 | + } \ |
| 926 | + } while(0) |
| 927 | + |
| 928 | +/// Override a print option within an OverrideScope. Works for any type. |
| 929 | +/// |
| 930 | +/// Signature is: |
| 931 | +/// void (OverrideScope &scope, <FIELD NAME>, T &&newValue) |
| 932 | +#define OVERRIDE_PRINT_OPTION_UNCONDITIONAL(SCOPE, FIELD_NAME, VALUE) \ |
| 933 | + do { \ |
| 934 | + auto finalizer = \ |
| 935 | + [_oldValue=(SCOPE).Options.FIELD_NAME](PrintOptions &opts) { \ |
| 936 | + opts.FIELD_NAME = _oldValue; \ |
| 937 | + }; \ |
| 938 | + (SCOPE).Options.FIELD_NAME = (VALUE); \ |
| 939 | + (SCOPE).addFinalizer(std::move(finalizer)); \ |
| 940 | + } while(0) |
| 941 | + |
| 942 | +} // end namespace swift |
828 | 943 |
|
829 | 944 | #endif // LLVM_SWIFT_AST_PRINTOPTIONS_H |
0 commit comments