Add SourceManager that can keep track of multiple source file syntax
nodes along with their external representations. The source manager can
emit diagnostics into any of those files, including tracking any
explicitly "detached" syntax nodes used for macro expansion.
Make sure we detach syntax nodes before passing them to macro
implementations, so they cannot see more of the source file than they
are permitted. We hadn't been doing this before (by accident), and
doing so motivated the introduction of the SourceManager.
Additionally, perform operator folding on macro arguments as part of
detaching them. Macro clients shouldn't have to do this, and moreover,
when clients do this, they lose the ability to easily emit diagnostics
on the now-folded nodes.
When emitting debug info that references into a macro expansion, dump
the macro expansion buffer into a file on disk (in the temporary
directory) so that one can see the macro expansion buffers in the
source files themselves.
The test here validates that the generated LLVM IR looks correct, but
I'm having a problem getting LLDB to actually locate the source code
correctly.
Add support for freestanding declaration macros.
- Parse `@declaration` attribute.
- Type check and expand `MacroExpansionDecl`.
Known issues:
- Generic macros are not yet handled.
- Expansion does not work when the parent decl context is `BraceStmt`. Need to parse freestanding declaration macro expansions in `BraceStmt` as `MacroExpansionDecl`, and add expanded decls to name lookup.
With macro expansions, and really any code generation that produces
proper source locations, the parent source file of a declaration
context will be a generated source file rather than the source file
near the top of the declaration-context stack. Adjust the
implementation of `getParentSourceFile()` to return that innermost
source file by doing location-based lookup.
Extend the serialized diagnostics file format to also support providing
the contents of source files, which can include a reference to the
"original source range" whose text is conceptually replaced with the
contents of the serialized diagnostics file, e.g., due to macro
expansion.
Align the grammar of macro declarations with SE-0382, so that macro
definitions are parsed as an expression. External macro definitions
are referenced via a referenced to the macro `#externalMacro`. Define
that macro in the standard library, and recognize uses of it as the
definition of other macros to use externally-defined macros. For
example, this means that the "stringify" macro used in a lot of
examples is now defined as something like this:
@expression macro stringify<T>(_ value: T) -> (T, String) =
#externalMacro(module: "MyMacros", type: "StringifyMacro")
We still parse the old "A.B" syntax for two reasons. First, it's
helpful to anyone who has existing code using the prior syntax, so they
get a warning + Fix-It to rewrite to the new syntax. Second, we use it
to define builtin macros like `externalMacro` itself, which looks like this:
@expression
public macro externalMacro<T>(module: String, type: String) -> T =
Builtin.ExternalMacro
This uses the same virtual `Builtin` module as other library builtins,
and we can expand it to handle other builtin macro implementations
(such as #line) over time.
Each macro expansion buffer was getting parsed twice: once by
ParseSourceFileRequest (which is used by unqualified name lookup) and
once to parse the expression when type-checking the expanded macro.
This meant that the same code had two ASTs. Hilarity ensures.
Stop directly invoking the parser on macro-expanded code. Instead, go
through ParseSourceFileRequest *as is always the right way*, and dig
out the expression we want.
The swift-syntax diagnostic system always treats Fix-Its as separate
notes, which are never attached to the primary diagnostic. Embrace this
module in the mapping over to the existing C++ diagnostic engine.
"Relink" the folded syntax node back into the primary syntax node. When
we do this, we get consistent source locations that do not require any
adjustment.
Test this by adding a Fix-It to the silly AddBlocker macro, replacing
the `+` with a `-`.