1717
1818#include " swift/AST/ASTContext.h"
1919#include " swift/AST/ASTWalker.h"
20+ #include " swift/Bridging/ASTGen.h"
2021#include " swift/AST/Decl.h"
2122#include " swift/AST/Expr.h"
2223#include " swift/AST/Initializer.h"
@@ -39,6 +40,104 @@ using namespace ast_scope;
3940
4041#pragma mark ASTScope
4142
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+
42141void ASTScope::unqualifiedLookup (
43142 SourceFile *SF, SourceLoc loc,
44143 namelookup::AbstractASTScopeDeclConsumer &consumer) {
@@ -48,7 +147,30 @@ void ASTScope::unqualifiedLookup(
48147
49148 if (auto *s = SF->getASTContext ().Stats )
50149 ++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+ }
52174}
53175
54176llvm::SmallVector<LabeledStmt *, 4 > ASTScope::lookupLabeledStmts (
0 commit comments