25
25
#include " swift/AST/Evaluator.h"
26
26
#include " swift/AST/Expr.h"
27
27
#include " swift/AST/TypeCheckRequests.h"
28
+ #include " swift/AST/TypeVisitor.h"
28
29
29
30
using namespace swift ;
30
31
31
32
bool swift::performanceHintDiagnosticsEnabled (ASTContext &ctx) {
32
- return !ctx.Diags .isIgnoredDiagnostic (diag::perf_hint_closure_returns_array.ID ) ||
33
- !ctx.Diags .isIgnoredDiagnostic (diag::perf_hint_function_returns_array.ID );
33
+ return !ctx.Diags .isIgnoredDiagnostic (
34
+ diag::perf_hint_closure_returns_array.ID ) ||
35
+ !ctx.Diags .isIgnoredDiagnostic (
36
+ diag::perf_hint_function_returns_array.ID ) ||
37
+ !ctx.Diags .isIgnoredDiagnostic (
38
+ diag::perf_hint_param_expects_existential_any.ID ) ||
39
+ !ctx.Diags .isIgnoredDiagnostic (
40
+ diag::perf_hint_func_returns_existential_any.ID ) ||
41
+ !ctx.Diags .isIgnoredDiagnostic (
42
+ diag::perf_hint_closure_returns_existential_any.ID ) ||
43
+ !ctx.Diags .isIgnoredDiagnostic (
44
+ diag::perf_hint_var_uses_existential_any.ID ) ||
45
+ !ctx.Diags .isIgnoredDiagnostic (
46
+ diag::perf_hint_any_pattern_uses_existential_any.ID ) ||
47
+ !ctx.Diags .isIgnoredDiagnostic (
48
+ diag::perf_hint_typealias_uses_existential_any.ID );
34
49
}
35
50
36
51
namespace {
@@ -52,6 +67,88 @@ void checkImplicitCopyReturnType(const ClosureExpr *Closure,
52
67
}
53
68
}
54
69
70
+ class CheckExistentialAny : public TypeVisitor <CheckExistentialAny, bool > {
71
+ public:
72
+ static bool inType (Type type) {
73
+ return CheckExistentialAny ().visit (type->getCanonicalType ());
74
+ }
75
+
76
+ static void inFunctionReturnType (FuncDecl *FD, DiagnosticEngine &Diags) {
77
+ Type T = FD->getResultInterfaceType ();
78
+
79
+ if (inType (T))
80
+ Diags.diagnose (FD, diag::perf_hint_func_returns_existential_any, FD);
81
+ }
82
+
83
+ static void inClosureReturnType (ClosureExpr *CE, DiagnosticEngine &Diags) {
84
+ Type T = CE->getResultType ();
85
+
86
+ if (inType (T))
87
+ Diags.diagnose (CE->getLoc (),
88
+ diag::perf_hint_closure_returns_existential_any);
89
+ }
90
+
91
+ static void inVariableType (const VarDecl *VD, DiagnosticEngine &Diags) {
92
+ Type T = VD->getInterfaceType ();
93
+
94
+ if (inType (T))
95
+ Diags.diagnose (VD, diag::perf_hint_var_uses_existential_any, VD);
96
+ }
97
+
98
+ static void inPatternType (const AnyPattern *AP, DiagnosticEngine &Diags) {
99
+ Type T = AP->getType ();
100
+
101
+ if (inType (T))
102
+ Diags.diagnose (AP->getLoc (),
103
+ diag::perf_hint_any_pattern_uses_existential_any);
104
+ }
105
+
106
+ static void inTypeAlias (const TypeAliasDecl *TAD, DiagnosticEngine &Diags) {
107
+ Type T = TAD->getUnderlyingType ();
108
+
109
+ if (inType (T))
110
+ Diags.diagnose (TAD->getLoc (),
111
+ diag::perf_hint_typealias_uses_existential_any, TAD);
112
+ }
113
+
114
+ bool visitExistentialType (ExistentialType *ET) {
115
+ return true ;
116
+ }
117
+
118
+ bool visitTupleType (TupleType *TT) {
119
+ for (const auto &element : TT->getElements ()) {
120
+ if (visit (element.getType ())) {
121
+ return true ;
122
+ }
123
+ }
124
+ return false ;
125
+ }
126
+
127
+ bool visitBoundGenericType (BoundGenericType *BGT) {
128
+ // Check generic arguments (e.g., Array<any Protocol>)
129
+ for (Type arg : BGT->getGenericArgs ()) {
130
+ if (visit (arg)) {
131
+ return true ;
132
+ }
133
+ }
134
+ return false ;
135
+ }
136
+
137
+ bool visitFunctionType (FunctionType *FT) {
138
+ for (const auto ¶m : FT->getParams ()) {
139
+ if (visit (param.getPlainType ()->getCanonicalType ())) {
140
+ return true ;
141
+ }
142
+ }
143
+
144
+ return visit (FT->getResult ()->getCanonicalType ());
145
+ }
146
+
147
+ bool visitType (TypeBase *T) {
148
+ return false ;
149
+ }
150
+ };
151
+
55
152
// / Produce performance hint diagnostics for a SourceFile.
56
153
class PerformanceHintDiagnosticWalker final : public ASTWalker {
57
154
ASTContext &Ctx;
@@ -64,16 +161,63 @@ class PerformanceHintDiagnosticWalker final : public ASTWalker {
64
161
SF->walk (Walker);
65
162
}
66
163
164
+ PreWalkResult<Pattern *> walkToPatternPre (Pattern *P) override {
165
+ if (P->isImplicit ())
166
+ return Action::SkipNode (P);
167
+
168
+ if (const AnyPattern *AP = dyn_cast<AnyPattern>(P)) {
169
+ CheckExistentialAny::inPatternType (AP, Ctx.Diags );
170
+ }
171
+
172
+ return Action::Continue (P);
173
+ }
174
+
67
175
PreWalkResult<Expr *> walkToExprPre (Expr *E) override {
68
- if (auto Closure = dyn_cast<ClosureExpr>(E))
176
+ if (E->isImplicit ())
177
+ return Action::SkipNode (E);
178
+
179
+ if (const ClosureExpr* Closure = dyn_cast<ClosureExpr>(E)) {
69
180
checkImplicitCopyReturnType (Closure, Ctx.Diags );
181
+ }
182
+
183
+ return Action::Continue (E);
184
+ }
185
+
186
+ PostWalkResult<Expr *> walkToExprPost (Expr *E) override {
187
+ assert (
188
+ !E->isImplicit () &&
189
+ " Traversing implicit expressions is disabled in the pre-walk visitor" );
190
+
191
+ if (auto Closure = dyn_cast<ClosureExpr>(E)) {
192
+ CheckExistentialAny::inClosureReturnType (Closure, Ctx.Diags );
193
+ }
70
194
71
195
return Action::Continue (E);
72
196
}
73
197
74
198
PreWalkAction walkToDeclPre (Decl *D) override {
75
- if (auto *FD = dyn_cast<FuncDecl>(D))
199
+ if (D->isImplicit ())
200
+ return Action::SkipNode ();
201
+
202
+ if (const FuncDecl *FD = dyn_cast<FuncDecl>(D)) {
76
203
checkImplicitCopyReturnType (FD, Ctx.Diags );
204
+ } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
205
+ CheckExistentialAny::inVariableType (VD, Ctx.Diags );
206
+ } else if (const TypeAliasDecl *TAD = dyn_cast<TypeAliasDecl>(D)) {
207
+ CheckExistentialAny::inTypeAlias (TAD, Ctx.Diags );
208
+ }
209
+
210
+ return Action::Continue ();
211
+ }
212
+
213
+ PostWalkAction walkToDeclPost (Decl *D) override {
214
+ assert (
215
+ !D->isImplicit () &&
216
+ " Traversing implicit declarations is disabled in the pre-walk visitor" );
217
+
218
+ if (auto *FD = dyn_cast<FuncDecl>(D)) {
219
+ CheckExistentialAny::inFunctionReturnType (FD, Ctx.Diags );
220
+ }
77
221
78
222
return Action::Continue ();
79
223
}
0 commit comments