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