15
15
16
16
#include " ObjCPropertyAttributeOrderFixer.h"
17
17
18
- #include " llvm/ADT/Sequence.h"
19
-
20
18
#include < algorithm>
21
19
22
20
namespace clang {
@@ -25,26 +23,20 @@ namespace format {
25
23
ObjCPropertyAttributeOrderFixer::ObjCPropertyAttributeOrderFixer (
26
24
const Environment &Env, const FormatStyle &Style)
27
25
: TokenAnalyzer(Env, Style) {
28
-
29
26
// Create an "order priority" map to use to sort properties.
30
- unsigned index = 0 ;
27
+ unsigned Index = 0 ;
31
28
for (const auto &Property : Style.ObjCPropertyAttributeOrder )
32
- SortOrderMap[Property] = index ++;
29
+ SortOrderMap[Property] = Index ++;
33
30
}
34
31
35
32
struct ObjCPropertyEntry {
36
- StringRef Attribute; // eg, " readwrite"
37
- StringRef Value; // eg, the " foo" of the attribute " getter=foo"
33
+ StringRef Attribute; // eg, ` readwrite`
34
+ StringRef Value; // eg, the ` foo` of the attribute ` getter=foo`
38
35
};
39
36
40
- static bool isObjCPropertyAttribute (const FormatToken *Tok) {
41
- // Most attributes look like identifiers, but `class` is a keyword.
42
- return Tok->isOneOf (tok::identifier, tok::kw_class);
43
- }
44
-
45
37
void ObjCPropertyAttributeOrderFixer::sortPropertyAttributes (
46
38
const SourceManager &SourceMgr, tooling::Replacements &Fixes,
47
- const FormatToken *BeginTok, const FormatToken *EndTok) const {
39
+ const FormatToken *BeginTok, const FormatToken *EndTok) {
48
40
assert (BeginTok);
49
41
assert (EndTok);
50
42
assert (EndTok->Previous );
@@ -53,22 +45,31 @@ void ObjCPropertyAttributeOrderFixer::sortPropertyAttributes(
53
45
if (BeginTok == EndTok || BeginTok->Next == EndTok)
54
46
return ;
55
47
48
+ // Use a set to sort attributes and remove duplicates.
49
+ std::set<unsigned > Ordinals;
50
+
51
+ // Create a "remapping index" on how to reorder the attributes.
52
+ SmallVector<int > Indices;
53
+
56
54
// Collect the attributes.
57
- SmallVector<ObjCPropertyEntry, 8 > PropertyAttributes;
55
+ SmallVector<ObjCPropertyEntry> PropertyAttributes;
56
+ bool HasDuplicates = false ;
57
+ int Index = 0 ;
58
58
for (auto Tok = BeginTok; Tok != EndTok; Tok = Tok->Next ) {
59
59
assert (Tok);
60
60
if (Tok->is (tok::comma)) {
61
61
// Ignore the comma separators.
62
62
continue ;
63
63
}
64
64
65
- if (!isObjCPropertyAttribute (Tok)) {
65
+ // Most attributes look like identifiers, but `class` is a keyword.
66
+ if (!Tok->isOneOf (tok::identifier, tok::kw_class)) {
66
67
// If we hit any other kind of token, just bail.
67
68
return ;
68
69
}
69
70
70
- // Memoize the attribute. (Note that 'class' is a legal attribute!)
71
- PropertyAttributes. push_back ({Tok-> TokenText , StringRef{}}) ;
71
+ const StringRef Attribute{Tok-> TokenText };
72
+ StringRef Value ;
72
73
73
74
// Also handle `getter=getFoo` attributes.
74
75
// (Note: no check needed against `EndTok`, since its type is not
@@ -82,49 +83,66 @@ void ObjCPropertyAttributeOrderFixer::sortPropertyAttributes(
82
83
return ;
83
84
}
84
85
Tok = Tok->Next ;
85
- PropertyAttributes.back ().Value = Tok->TokenText ;
86
+ Value = Tok->TokenText ;
87
+ }
88
+
89
+ auto It = SortOrderMap.find (Attribute);
90
+ if (It == SortOrderMap.end ())
91
+ It = SortOrderMap.insert ({Attribute, SortOrderMap.size ()}).first ;
92
+
93
+ // Sort the indices based on the priority stored in `SortOrderMap`.
94
+ const auto Ordinal = It->second ;
95
+ if (!Ordinals.insert (Ordinal).second ) {
96
+ HasDuplicates = true ;
97
+ continue ;
86
98
}
99
+
100
+ if (Ordinal >= Indices.size ())
101
+ Indices.resize (Ordinal + 1 );
102
+ Indices[Ordinal] = Index++;
103
+
104
+ // Memoize the attribute.
105
+ PropertyAttributes.push_back ({Attribute, Value});
87
106
}
88
107
89
- // There's nothing to do unless there's more than one attribute.
90
- if (PropertyAttributes.size () < 2 )
91
- return ;
108
+ if (!HasDuplicates) {
109
+ // There's nothing to do unless there's more than one attribute.
110
+ if (PropertyAttributes.size () < 2 )
111
+ return ;
92
112
93
- // Create a "remapping index" on how to reorder the attributes.
94
- SmallVector<unsigned , 8 > Indices =
95
- llvm::to_vector<8 >(llvm::seq<unsigned >(0 , PropertyAttributes.size ()));
96
-
97
- // Sort the indices based on the priority stored in 'SortOrderMap'; use Max
98
- // for missing values.
99
- const auto SortOrderMax = Style.ObjCPropertyAttributeOrder .size ();
100
- auto SortIndex = [&](const StringRef &Needle) -> unsigned {
101
- auto I = SortOrderMap.find (Needle);
102
- return (I == SortOrderMap.end ()) ? SortOrderMax : I->getValue ();
103
- };
104
- llvm::stable_sort (Indices, [&](unsigned LHSI, unsigned RHSI) {
105
- return SortIndex (PropertyAttributes[LHSI].Attribute ) <
106
- SortIndex (PropertyAttributes[RHSI].Attribute );
107
- });
108
-
109
- // If the property order is already correct, then no fix-up is needed.
110
- if (llvm::is_sorted (Indices))
111
- return ;
113
+ int PrevIndex = -1 ;
114
+ bool IsSorted = true ;
115
+ for (const auto Ordinal : Ordinals) {
116
+ const auto Index = Indices[Ordinal];
117
+ if (Index < PrevIndex) {
118
+ IsSorted = false ;
119
+ break ;
120
+ }
121
+ assert (Index > PrevIndex);
122
+ PrevIndex = Index;
123
+ }
124
+
125
+ // If the property order is already correct, then no fix-up is needed.
126
+ if (IsSorted)
127
+ return ;
128
+ }
112
129
113
130
// Generate the replacement text.
114
131
std::string NewText;
115
- const auto AppendAttribute = [&](const ObjCPropertyEntry &PropertyEntry) {
132
+ bool IsFirst = true ;
133
+ for (const auto Ordinal : Ordinals) {
134
+ if (IsFirst)
135
+ IsFirst = false ;
136
+ else
137
+ NewText += " , " ;
138
+
139
+ const auto &PropertyEntry = PropertyAttributes[Indices[Ordinal]];
116
140
NewText += PropertyEntry.Attribute ;
117
141
118
- if (! PropertyEntry.Value .empty ()) {
119
- NewText += " = " ;
120
- NewText += PropertyEntry. Value ;
142
+ if (const auto Value = PropertyEntry.Value ; ! Value.empty ()) {
143
+ NewText += ' = ' ;
144
+ NewText += Value;
121
145
}
122
- };
123
-
124
- AppendAttribute (PropertyAttributes[Indices[0 ]]);
125
- for (unsigned Index : llvm::drop_begin (Indices)) {
126
- NewText += " , " ;
127
- AppendAttribute (PropertyAttributes[Index]);
128
146
}
129
147
130
148
auto Range = CharSourceRange::getCharRange (
@@ -139,7 +157,7 @@ void ObjCPropertyAttributeOrderFixer::sortPropertyAttributes(
139
157
140
158
void ObjCPropertyAttributeOrderFixer::analyzeObjCPropertyDecl (
141
159
const SourceManager &SourceMgr, const AdditionalKeywords &Keywords,
142
- tooling::Replacements &Fixes, const FormatToken *Tok) const {
160
+ tooling::Replacements &Fixes, const FormatToken *Tok) {
143
161
assert (Tok);
144
162
145
163
// Expect `property` to be the very next token or else just bail early.
0 commit comments