Skip to content

Commit 1d94844

Browse files
committed
Add SwiftLexicalLookup validation.
1 parent 04f5f33 commit 1d94844

File tree

9 files changed

+775
-1
lines changed

9 files changed

+775
-1
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,26 @@ struct BridgedLocatedIdentifier {
8585
BridgedSourceLoc NameLoc;
8686
};
8787

88+
struct BridgedConsumedLookupResult {
89+
SWIFT_NAME("name")
90+
BridgedIdentifier Name;
91+
92+
SWIFT_NAME("nameLoc")
93+
BridgedSourceLoc NameLoc;
94+
95+
SWIFT_NAME("flag")
96+
SwiftInt Flag;
97+
98+
#ifdef USED_IN_CPP_SOURCE
99+
BridgedConsumedLookupResult(swift::Identifier name,
100+
swift::SourceLoc sourceLoc,
101+
SwiftInt flag
102+
) : Name(BridgedIdentifier(name)),
103+
NameLoc(BridgedSourceLoc(sourceLoc)),
104+
Flag(flag) {}
105+
#endif
106+
};
107+
88108
class BridgedDeclBaseName {
89109
BridgedIdentifier Ident;
90110

include/swift/AST/DiagnosticsCommon.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,13 @@ NOTE(in_macro_expansion,none,
232232
ERROR(macro_experimental,none,
233233
"%0 macros are an experimental feature that is not enabled %select{|(%1)}1",
234234
(StringRef, StringRef))
235+
236+
//------------------------------------------------------------------------------
237+
// MARK: lexical lookup diagnostics
238+
//------------------------------------------------------------------------------
239+
240+
ERROR(lookup_outputs_dont_match,none,
241+
"Unqualified lookup output from ASTScope and SwiftLexicalLookup don't match", ())
235242

236243
//------------------------------------------------------------------------------
237244
// MARK: bridged diagnostics

include/swift/Basic/Features.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,10 @@ EXPERIMENTAL_FEATURE(ParserRoundTrip, false)
301301
/// Swift parser.
302302
EXPERIMENTAL_FEATURE(ParserValidation, false)
303303

304+
/// Whether to perform validation of the unqualified lookup produced by
305+
/// ASTScope and SwiftLexicalLookup
306+
EXPERIMENTAL_FEATURE(UnqualifiedLookupValidation, false)
307+
304308
/// Whether to emit diagnostics from the new parser first, and only emit
305309
/// diagnostics from the existing parser when there are none from the new
306310
/// parser.

include/swift/Bridging/ASTGen.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ intptr_t swift_ASTGen_configuredRegions(
117117
void swift_ASTGen_freeConfiguredRegions(
118118
BridgedIfConfigClauseRangeInfo *_Nullable regions, intptr_t numRegions);
119119

120+
bool swift_ASTGen_validateUnqualifiedLookup(
121+
void *_Nonnull sourceFile,
122+
BridgedASTContext astContext,
123+
BridgedSourceLoc sourceLoc,
124+
bool finishInSequentialScope,
125+
BridgedArrayRef astScopeResultRef);
126+
120127
#ifdef __cplusplus
121128
}
122129
#endif

lib/AST/ASTScope.cpp

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
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,103 @@ using namespace ast_scope;
3940

4041
#pragma mark ASTScope
4142

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+
42140
void ASTScope::unqualifiedLookup(
43141
SourceFile *SF, SourceLoc loc,
44142
namelookup::AbstractASTScopeDeclConsumer &consumer) {
@@ -48,7 +146,30 @@ void ASTScope::unqualifiedLookup(
48146

49147
if (auto *s = SF->getASTContext().Stats)
50148
++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+
}
52173
}
53174

54175
llvm::SmallVector<LabeledStmt *, 4> ASTScope::lookupLabeledStmts(

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ UNINTERESTING_FEATURE(OpaqueTypeErasure)
103103
UNINTERESTING_FEATURE(PackageCMO)
104104
UNINTERESTING_FEATURE(ParserRoundTrip)
105105
UNINTERESTING_FEATURE(ParserValidation)
106+
UNINTERESTING_FEATURE(UnqualifiedLookupValidation)
106107
UNINTERESTING_FEATURE(ParserDiagnostics)
107108
UNINTERESTING_FEATURE(ImplicitSome)
108109
UNINTERESTING_FEATURE(ParserASTGen)

lib/ASTGen/Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ let package = Package(
5656
dependencies: [
5757
.product(name: "SwiftDiagnostics", package: "swift-syntax"),
5858
.product(name: "SwiftIfConfig", package: "swift-syntax"),
59+
.product(name: "SwiftLexicalLookup", package: "swift-syntax"),
5960
.product(name: "SwiftOperators", package: "swift-syntax"),
6061
.product(name: "SwiftParser", package: "swift-syntax"),
6162
.product(name: "SwiftParserDiagnostics", package: "swift-syntax"),

lib/ASTGen/Sources/ASTGen/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP
1010
Exprs.swift
1111
Generics.swift
1212
LegacyParse.swift
13+
LexicalLookup.swift
1314
Literals.swift
1415
ParameterClause.swift
1516
Patterns.swift
@@ -25,6 +26,7 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP
2526
_CompilerRegexParser
2627
_CompilerSwiftSyntax
2728
_CompilerSwiftIfConfig
29+
_CompilerSwiftLexicalLookup
2830
_CompilerSwiftOperators
2931
_CompilerSwiftSyntaxBuilder
3032
_CompilerSwiftParser

0 commit comments

Comments
 (0)