17
17
18
18
#include " swift/AST/ASTContext.h"
19
19
#include " swift/AST/ASTWalker.h"
20
+ #include " swift/Bridging/ASTGen.h"
20
21
#include " swift/AST/Decl.h"
21
22
#include " swift/AST/Expr.h"
22
23
#include " swift/AST/Initializer.h"
@@ -39,6 +40,103 @@ using namespace ast_scope;
39
40
40
41
#pragma mark ASTScope
41
42
43
+ class LoggingASTScopeDeclConsumer
44
+ : public namelookup::AbstractASTScopeDeclConsumer {
45
+ private:
46
+ namelookup::AbstractASTScopeDeclConsumer *originalConsumer;
47
+
48
+ public:
49
+ mutable SmallVector<BridgedConsumedLookupResult> recordedElements;
50
+
51
+ LoggingASTScopeDeclConsumer (
52
+ namelookup::AbstractASTScopeDeclConsumer *consumer)
53
+ : originalConsumer(consumer) {}
54
+
55
+ ~LoggingASTScopeDeclConsumer () = default ;
56
+
57
+ // / Called for every ValueDecl visible from the lookup.
58
+ // /
59
+ // / Takes an array in order to batch the consumption before setting
60
+ // / IndexOfFirstOuterResult when necessary.
61
+ // /
62
+ // / Additionally, each name is logged to `recordedElements` and
63
+ // / can be later used in validation of `SwiftLexicalLookup` result.
64
+ // /
65
+ // / \param baseDC either a type context or the local context of a
66
+ // / `self` parameter declaration. See LookupResult for a discussion
67
+ // / of type -vs- instance lookup results.
68
+ // /
69
+ // / \return true if the lookup should be stopped at this point.
70
+ bool consume (ArrayRef<ValueDecl *> values,
71
+ NullablePtr<DeclContext> baseDC = nullptr ) override {
72
+ bool result = originalConsumer->consume (values, baseDC);
73
+
74
+ for (auto value : values) {
75
+ if (auto sourceLoc = value->getLoc ()) {
76
+ recordedElements.push_back (BridgedConsumedLookupResult (
77
+ value->getBaseIdentifier (), sourceLoc, result));
78
+ } else {
79
+ // If sourceLoc is unavailable, use location of it's parent.
80
+ recordedElements.push_back (BridgedConsumedLookupResult (
81
+ value->getBaseIdentifier (),
82
+ value->getDeclContext ()->getAsDecl ()->getLoc (), result));
83
+ }
84
+ }
85
+
86
+ return result;
87
+ };
88
+
89
+ // / Look for members of a nominal type or extension scope.
90
+ // /
91
+ // / Each call is recorded in `recordedElements` with a special flag set.
92
+ // / It can be later used in validation of `SwiftLexicalLookup` result.
93
+ // /
94
+ // / \return true if the lookup should be stopped at this point.
95
+ bool lookInMembers (const DeclContext *scopeDC) const override {
96
+ bool result = originalConsumer->lookInMembers (scopeDC);
97
+
98
+ if (auto *extDecl = dyn_cast<ExtensionDecl>(scopeDC)) {
99
+ recordedElements.push_back (BridgedConsumedLookupResult (
100
+ Identifier (), extDecl->getExtendedTypeRepr ()->getLoc (),
101
+ 0b10 + result));
102
+ } else {
103
+ recordedElements.push_back (BridgedConsumedLookupResult (
104
+ scopeDC->getSelfNominalTypeDecl ()->getBaseIdentifier (),
105
+ scopeDC->getAsDecl ()->getLoc (), 0b10 + result));
106
+ }
107
+
108
+ return result;
109
+ };
110
+
111
+ // / Called for local VarDecls that might not yet be in scope.
112
+ // /
113
+ // / Note that the set of VarDecls visited here are going to be a
114
+ // / superset of those visited in consume().
115
+ bool consumePossiblyNotInScope (ArrayRef<VarDecl *> values) override {
116
+ bool result = originalConsumer->consumePossiblyNotInScope (values);
117
+ return result;
118
+ }
119
+
120
+ // / Called right before looking at the parent scope of a BraceStmt.
121
+ // /
122
+ // / \return true if the lookup should be stopped at this point.
123
+ bool finishLookupInBraceStmt (BraceStmt *stmt) override {
124
+ return originalConsumer->finishLookupInBraceStmt (stmt);
125
+ }
126
+
127
+ #ifndef NDEBUG
128
+ void startingNextLookupStep () override {
129
+ originalConsumer->startingNextLookupStep ();
130
+ }
131
+ void finishingLookup (std::string input) const override {
132
+ originalConsumer->finishingLookup (input);
133
+ }
134
+ bool isTargetLookup () const override {
135
+ return originalConsumer->isTargetLookup ();
136
+ }
137
+ #endif
138
+ };
139
+
42
140
void ASTScope::unqualifiedLookup (
43
141
SourceFile *SF, SourceLoc loc,
44
142
namelookup::AbstractASTScopeDeclConsumer &consumer) {
@@ -48,7 +146,30 @@ void ASTScope::unqualifiedLookup(
48
146
49
147
if (auto *s = SF->getASTContext ().Stats )
50
148
++s->getFrontendCounters ().NumASTScopeLookups ;
51
- ASTScopeImpl::unqualifiedLookup (SF, loc, consumer);
149
+
150
+ // Perform validation of SwiftLexicalLookup if option
151
+ // Feature::UnqualifiedLookupValidation is enabled and lookup was not
152
+ // performed in a macro.
153
+ if (SF->getASTContext ().LangOpts .hasFeature (
154
+ Feature::UnqualifiedLookupValidation) &&
155
+ !SF->getEnclosingSourceFile ()) {
156
+ LoggingASTScopeDeclConsumer loggingASTScopeDeclConsumer =
157
+ LoggingASTScopeDeclConsumer (&consumer);
158
+
159
+ ASTScopeImpl::unqualifiedLookup (SF, loc, loggingASTScopeDeclConsumer);
160
+
161
+ bool passed = swift_ASTGen_validateUnqualifiedLookup (
162
+ SF->getExportedSourceFile (), SF->getASTContext (), loc,
163
+ loggingASTScopeDeclConsumer.finishLookupInBraceStmt (nullptr ),
164
+ BridgedArrayRef (loggingASTScopeDeclConsumer.recordedElements .data (),
165
+ loggingASTScopeDeclConsumer.recordedElements .size ()));
166
+
167
+ if (!passed) {
168
+ SF->getASTContext ().Diags .diagnose (loc, diag::lookup_outputs_dont_match);
169
+ }
170
+ } else {
171
+ ASTScopeImpl::unqualifiedLookup (SF, loc, consumer);
172
+ }
52
173
}
53
174
54
175
llvm::SmallVector<LabeledStmt *, 4 > ASTScope::lookupLabeledStmts (
0 commit comments