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.ID ) ||
39
+ !ctx.Diags .isIgnoredDiagnostic (
40
+ diag::perf_hint_func_returns_existential.ID ) ||
41
+ !ctx.Diags .isIgnoredDiagnostic (
42
+ diag::perf_hint_closure_returns_existential.ID ) ||
43
+ !ctx.Diags .isIgnoredDiagnostic (
44
+ diag::perf_hint_var_uses_existential.ID ) ||
45
+ !ctx.Diags .isIgnoredDiagnostic (
46
+ diag::perf_hint_any_pattern_uses_existential.ID ) ||
47
+ !ctx.Diags .isIgnoredDiagnostic (
48
+ diag::perf_hint_typealias_uses_existential.ID );
34
49
}
35
50
36
51
namespace {
@@ -52,6 +67,52 @@ void checkImplicitCopyReturnType(const ClosureExpr *Closure,
52
67
}
53
68
}
54
69
70
+ bool hasExistentialAnyInType (Type T) {
71
+ return T->getCanonicalType ().findIf (
72
+ [](CanType CT) { return isa<ExistentialType>(CT); });
73
+ }
74
+
75
+ void checkExistentialInFunctionReturnType (const FuncDecl *FD,
76
+ DiagnosticEngine &Diags) {
77
+ Type T = FD->getResultInterfaceType ();
78
+
79
+ if (hasExistentialAnyInType (T))
80
+ Diags.diagnose (FD, diag::perf_hint_func_returns_existential, FD);
81
+ }
82
+
83
+ void checkExistentialInClosureReturnType (const ClosureExpr *CE,
84
+ DiagnosticEngine &Diags) {
85
+ Type T = CE->getResultType ();
86
+
87
+ if (hasExistentialAnyInType (T))
88
+ Diags.diagnose (CE->getLoc (), diag::perf_hint_closure_returns_existential);
89
+ }
90
+
91
+ void checkExistentialInVariableType (const VarDecl *VD,
92
+ DiagnosticEngine &Diags) {
93
+ Type T = VD->getInterfaceType ();
94
+
95
+ if (hasExistentialAnyInType (T))
96
+ Diags.diagnose (VD, diag::perf_hint_var_uses_existential, VD);
97
+ }
98
+
99
+ void checkExistentialInPatternType (const AnyPattern *AP,
100
+ DiagnosticEngine &Diags) {
101
+ Type T = AP->getType ();
102
+
103
+ if (hasExistentialAnyInType (T))
104
+ Diags.diagnose (AP->getLoc (), diag::perf_hint_any_pattern_uses_existential);
105
+ }
106
+
107
+ void checkExistentialInTypeAlias (const TypeAliasDecl *TAD,
108
+ DiagnosticEngine &Diags) {
109
+ Type T = TAD->getUnderlyingType ();
110
+
111
+ if (hasExistentialAnyInType (T))
112
+ Diags.diagnose (TAD->getLoc (), diag::perf_hint_typealias_uses_existential,
113
+ TAD);
114
+ }
115
+
55
116
// / Produce performance hint diagnostics for a SourceFile.
56
117
class PerformanceHintDiagnosticWalker final : public ASTWalker {
57
118
ASTContext &Ctx;
@@ -64,16 +125,64 @@ class PerformanceHintDiagnosticWalker final : public ASTWalker {
64
125
SF->walk (Walker);
65
126
}
66
127
128
+ PreWalkResult<Pattern *> walkToPatternPre (Pattern *P) override {
129
+ if (P->isImplicit ())
130
+ return Action::SkipNode (P);
131
+
132
+ return Action::Continue (P);
133
+ }
134
+
135
+ PostWalkResult<Pattern *> walkToPatternPost (Pattern *P) override {
136
+ assert (!P->isImplicit () &&
137
+ " Traversing implicit patterns is disabled in the pre-walk visitor" );
138
+
139
+ if (const AnyPattern *AP = dyn_cast<AnyPattern>(P)) {
140
+ checkExistentialInPatternType (AP, Ctx.Diags );
141
+ }
142
+
143
+ return Action::Continue (P);
144
+ }
145
+
67
146
PreWalkResult<Expr *> walkToExprPre (Expr *E) override {
68
- if (auto Closure = dyn_cast<ClosureExpr>(E))
69
- checkImplicitCopyReturnType (Closure, Ctx.Diags );
147
+ if (E->isImplicit ())
148
+ return Action::SkipNode (E);
149
+
150
+ return Action::Continue (E);
151
+ }
152
+
153
+ PostWalkResult<Expr *> walkToExprPost (Expr *E) override {
154
+ assert (
155
+ !E->isImplicit () &&
156
+ " Traversing implicit expressions is disabled in the pre-walk visitor" );
157
+
158
+ if (const ClosureExpr *CE = dyn_cast<ClosureExpr>(E)) {
159
+ checkImplicitCopyReturnType (CE, Ctx.Diags );
160
+ checkExistentialInClosureReturnType (CE, Ctx.Diags );
161
+ }
70
162
71
163
return Action::Continue (E);
72
164
}
73
165
74
166
PreWalkAction walkToDeclPre (Decl *D) override {
75
- if (auto *FD = dyn_cast<FuncDecl>(D))
167
+ if (D->isImplicit ())
168
+ return Action::SkipNode ();
169
+
170
+ return Action::Continue ();
171
+ }
172
+
173
+ PostWalkAction walkToDeclPost (Decl *D) override {
174
+ assert (
175
+ !D->isImplicit () &&
176
+ " Traversing implicit declarations is disabled in the pre-walk visitor" );
177
+
178
+ if (const FuncDecl *FD = dyn_cast<FuncDecl>(D)) {
76
179
checkImplicitCopyReturnType (FD, Ctx.Diags );
180
+ checkExistentialInFunctionReturnType (FD, Ctx.Diags );
181
+ } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
182
+ checkExistentialInVariableType (VD, Ctx.Diags );
183
+ } else if (const TypeAliasDecl *TAD = dyn_cast<TypeAliasDecl>(D)) {
184
+ checkExistentialInTypeAlias (TAD, Ctx.Diags );
185
+ }
77
186
78
187
return Action::Continue ();
79
188
}
0 commit comments