|
20 | 20 | #include "swift/Syntax/References.h"
|
21 | 21 | #include "swift/Syntax/Syntax.h"
|
22 | 22 | #include "swift/Syntax/SyntaxFactory.h"
|
| 23 | +#include "swift/Syntax/SyntaxVisitor.h" |
23 | 24 | #include "swift/Syntax/TokenKinds.h"
|
24 | 25 | #include "swift/Syntax/TokenSyntax.h"
|
25 | 26 | #include "swift/Syntax/Trivia.h"
|
@@ -52,10 +53,12 @@ RC<RawSyntax> createSyntaxAs(SyntaxKind Kind, ArrayRef<RC<RawSyntax>> Parts) {
|
52 | 53 |
|
53 | 54 | SyntaxParsingContext::SyntaxParsingContext(SyntaxParsingContext *&CtxtHolder,
|
54 | 55 | SourceFile &SF,
|
55 |
| - DiagnosticEngine &Diags) |
56 |
| - : RootDataOrParent(new RootContextData(SF, Diags)), CtxtHolder(CtxtHolder), |
57 |
| - Storage(getRootData().Storage), Offset(0), Mode(AccumulationMode::Root), |
58 |
| - Enabled(SF.shouldKeepSyntaxInfo()) { |
| 56 | + DiagnosticEngine &Diags, |
| 57 | + SourceManager &SourceMgr, |
| 58 | + unsigned BufferID) |
| 59 | + : RootDataOrParent(new RootContextData(SF, Diags, SourceMgr, BufferID)), |
| 60 | + CtxtHolder(CtxtHolder), Storage(getRootData().Storage), Offset(0), |
| 61 | + Mode(AccumulationMode::Root), Enabled(SF.shouldKeepSyntaxInfo()) { |
59 | 62 | CtxtHolder = this;
|
60 | 63 | }
|
61 | 64 |
|
@@ -214,7 +217,37 @@ RC<RawSyntax> bridgeAs(SyntaxContextKind Kind, ArrayRef<RC<RawSyntax>> Parts) {
|
214 | 217 | }
|
215 | 218 | }
|
216 | 219 |
|
217 |
| -void finalizeSourceFile(SourceFile &SF, ArrayRef<RC<RawSyntax>> Parts) { |
| 220 | +/// This verifier traverses a syntax node to emit proper diagnostics. |
| 221 | +class SyntaxVerifier: public SyntaxVisitor { |
| 222 | + SourceFileSyntax Root; |
| 223 | + RootContextData &RootData; |
| 224 | + template<class T> |
| 225 | + SourceLoc getSourceLoc(T Node) { |
| 226 | + return RootData.SourceMgr.getLocForOffset(RootData.BufferID, |
| 227 | + Node.getAbsolutePosition(Root).getOffset()); |
| 228 | + } |
| 229 | +public: |
| 230 | + SyntaxVerifier(SourceFileSyntax Root, RootContextData &RootData) : |
| 231 | + Root(Root), RootData(RootData) {} |
| 232 | + void visit(UnknownDeclSyntax Node) override { |
| 233 | + RootData.Diags.diagnose(getSourceLoc(Node), diag::unknown_syntax_entity, |
| 234 | + "declaration"); |
| 235 | + visitChildren(Node); |
| 236 | + } |
| 237 | + void visit(UnknownExprSyntax Node) override { |
| 238 | + RootData.Diags.diagnose(getSourceLoc(Node), diag::unknown_syntax_entity, |
| 239 | + "expression"); |
| 240 | + visitChildren(Node); |
| 241 | + } |
| 242 | + |
| 243 | + void verify(Syntax Node) { |
| 244 | + Node.accept(*this); |
| 245 | + } |
| 246 | +}; |
| 247 | + |
| 248 | +void finalizeSourceFile(RootContextData &RootData, |
| 249 | + ArrayRef<RC<RawSyntax>> Parts) { |
| 250 | + SourceFile &SF = RootData.SF; |
218 | 251 | std::vector<DeclSyntax> AllTopLevel;
|
219 | 252 | llvm::Optional<TokenSyntax> EOFToken;
|
220 | 253 |
|
@@ -242,6 +275,14 @@ void finalizeSourceFile(SourceFile &SF, ArrayRef<RC<RawSyntax>> Parts) {
|
242 | 275 | SyntaxFactory::makeDeclList(AllTopLevel),
|
243 | 276 | EOFToken.hasValue() ? *EOFToken
|
244 | 277 | : TokenSyntax::missingToken(tok::eof, "")));
|
| 278 | + |
| 279 | + if (SF.getASTContext().LangOpts.VerifySyntaxTree) { |
| 280 | + // Verify the added nodes if specified. |
| 281 | + SyntaxVerifier Verifier(SF.getSyntaxRoot(), RootData); |
| 282 | + for (auto RawNode: Parts) { |
| 283 | + Verifier.verify(make<Syntax>(RawNode)); |
| 284 | + } |
| 285 | + } |
245 | 286 | }
|
246 | 287 | } // End of anonymous namespace
|
247 | 288 |
|
@@ -294,7 +335,7 @@ SyntaxParsingContext::~SyntaxParsingContext() {
|
294 | 335 | // Accumulate parsed toplevel syntax onto the SourceFile.
|
295 | 336 | case AccumulationMode::Root:
|
296 | 337 | assert(isRoot() && "AccumulationMode::Root is only for root context");
|
297 |
| - finalizeSourceFile(getRootData().SF, getParts()); |
| 338 | + finalizeSourceFile(getRootData(), getParts()); |
298 | 339 | break;
|
299 | 340 |
|
300 | 341 | // Never.
|
|
0 commit comments