clang 19.0.0git
IncrementalParser.cpp
Go to the documentation of this file.
1//===--------- IncrementalParser.cpp - Incremental Compilation -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the class which performs incremental code compilation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "IncrementalParser.h"
14
23#include "clang/Parse/Parser.h"
24#include "clang/Sema/Sema.h"
25#include "llvm/Option/ArgList.h"
26#include "llvm/Support/CrashRecoveryContext.h"
27#include "llvm/Support/Error.h"
28#include "llvm/Support/Timer.h"
29
30#include <sstream>
31
32namespace clang {
33
34class IncrementalASTConsumer final : public ASTConsumer {
35 Interpreter &Interp;
36 std::unique_ptr<ASTConsumer> Consumer;
37
38public:
39 IncrementalASTConsumer(Interpreter &InterpRef, std::unique_ptr<ASTConsumer> C)
40 : Interp(InterpRef), Consumer(std::move(C)) {}
41
42 bool HandleTopLevelDecl(DeclGroupRef DGR) override final {
43 if (DGR.isNull())
44 return true;
45 if (!Consumer)
46 return true;
47
48 for (Decl *D : DGR)
49 if (auto *TSD = llvm::dyn_cast<TopLevelStmtDecl>(D);
50 TSD && TSD->isSemiMissing())
51 TSD->setStmt(Interp.SynthesizeExpr(cast<Expr>(TSD->getStmt())));
52
53 return Consumer->HandleTopLevelDecl(DGR);
54 }
55 void HandleTranslationUnit(ASTContext &Ctx) override final {
56 Consumer->HandleTranslationUnit(Ctx);
57 }
59 Consumer->HandleInlineFunctionDefinition(D);
60 }
61 void HandleInterestingDecl(DeclGroupRef D) override final {
62 Consumer->HandleInterestingDecl(D);
63 }
64 void HandleTagDeclDefinition(TagDecl *D) override final {
65 Consumer->HandleTagDeclDefinition(D);
66 }
67 void HandleTagDeclRequiredDefinition(const TagDecl *D) override final {
68 Consumer->HandleTagDeclRequiredDefinition(D);
69 }
71 Consumer->HandleCXXImplicitFunctionInstantiation(D);
72 }
74 Consumer->HandleTopLevelDeclInObjCContainer(D);
75 }
76 void HandleImplicitImportDecl(ImportDecl *D) override final {
77 Consumer->HandleImplicitImportDecl(D);
78 }
79 void CompleteTentativeDefinition(VarDecl *D) override final {
80 Consumer->CompleteTentativeDefinition(D);
81 }
82 void CompleteExternalDeclaration(VarDecl *D) override final {
83 Consumer->CompleteExternalDeclaration(D);
84 }
85 void AssignInheritanceModel(CXXRecordDecl *RD) override final {
86 Consumer->AssignInheritanceModel(RD);
87 }
89 Consumer->HandleCXXStaticMemberVarInstantiation(D);
90 }
91 void HandleVTable(CXXRecordDecl *RD) override final {
92 Consumer->HandleVTable(RD);
93 }
95 return Consumer->GetASTMutationListener();
96 }
98 return Consumer->GetASTDeserializationListener();
99 }
100 void PrintStats() override final { Consumer->PrintStats(); }
101 bool shouldSkipFunctionBody(Decl *D) override final {
102 return Consumer->shouldSkipFunctionBody(D);
103 }
104 static bool classof(const clang::ASTConsumer *) { return true; }
105};
106
107/// A custom action enabling the incremental processing functionality.
108///
109/// The usual \p FrontendAction expects one call to ExecuteAction and once it
110/// sees a call to \p EndSourceFile it deletes some of the important objects
111/// such as \p Preprocessor and \p Sema assuming no further input will come.
112///
113/// \p IncrementalAction ensures it keep its underlying action's objects alive
114/// as long as the \p IncrementalParser needs them.
115///
117private:
118 bool IsTerminating = false;
119
120public:
121 IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
122 llvm::Error &Err)
123 : WrapperFrontendAction([&]() {
124 llvm::ErrorAsOutParameter EAO(&Err);
125 std::unique_ptr<FrontendAction> Act;
126 switch (CI.getFrontendOpts().ProgramAction) {
127 default:
128 Err = llvm::createStringError(
129 std::errc::state_not_recoverable,
130 "Driver initialization failed. "
131 "Incremental mode for action %d is not supported",
133 return Act;
135 [[fallthrough]];
137 [[fallthrough]];
139 Act = CreateFrontendAction(CI);
140 break;
142 [[fallthrough]];
144 [[fallthrough]];
145 case frontend::EmitBC:
146 [[fallthrough]];
148 [[fallthrough]];
150 [[fallthrough]];
152 Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
153 break;
154 }
155 return Act;
156 }()) {}
157 FrontendAction *getWrapped() const { return WrappedAction.get(); }
159 return TU_Incremental;
160 }
161
162 void ExecuteAction() override {
164 assert(CI.hasPreprocessor() && "No PP!");
165
166 // Use a code completion consumer?
167 CodeCompleteConsumer *CompletionConsumer = nullptr;
169 CompletionConsumer = &CI.getCodeCompletionConsumer();
170
171 Preprocessor &PP = CI.getPreprocessor();
173
174 if (!CI.hasSema())
175 CI.createSema(getTranslationUnitKind(), CompletionConsumer);
176 }
177
178 // Do not terminate after processing the input. This allows us to keep various
179 // clang objects alive and to incrementally grow the current TU.
180 void EndSourceFile() override {
181 // The WrappedAction can be nullptr if we issued an error in the ctor.
182 if (IsTerminating && getWrapped())
184 }
185
187 assert(!IsTerminating && "Already finalized!");
188 IsTerminating = true;
190 }
191};
192
194 FrontendAction *WrappedAct = Act->getWrapped();
195 if (!WrappedAct->hasIRSupport())
196 return nullptr;
197 return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
198}
199
201
203 std::unique_ptr<CompilerInstance> Instance,
204 llvm::LLVMContext &LLVMCtx,
205 llvm::Error &Err)
206 : CI(std::move(Instance)) {
207 llvm::ErrorAsOutParameter EAO(&Err);
208 Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
209 if (Err)
210 return;
211 CI->ExecuteAction(*Act);
212
213 if (getCodeGen())
215
216 std::unique_ptr<ASTConsumer> IncrConsumer =
217 std::make_unique<IncrementalASTConsumer>(Interp, CI->takeASTConsumer());
218 CI->setASTConsumer(std::move(IncrConsumer));
219 Consumer = &CI->getASTConsumer();
220 P.reset(
221 new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
222 P->Initialize();
223
224 // An initial PTU is needed as CUDA includes some headers automatically
225 auto PTU = ParseOrWrapTopLevelDecl();
226 if (auto E = PTU.takeError()) {
227 consumeError(std::move(E)); // FIXME
228 return; // PTU.takeError();
229 }
230
231 if (getCodeGen()) {
232 PTU->TheModule = GenModule();
233 assert(PTU->TheModule && "Failed to create initial PTU");
234 }
235}
236
238 P.reset();
239 Act->FinalizeAction();
240}
241
243IncrementalParser::ParseOrWrapTopLevelDecl() {
244 // Recover resources if we crash before exiting this method.
245 Sema &S = CI->getSema();
246 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
247 Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
248 Sema::LocalEagerInstantiationScope LocalInstantiations(S);
249
250 PTUs.emplace_back(PartialTranslationUnit());
251 PartialTranslationUnit &LastPTU = PTUs.back();
252 // Add a new PTU.
253 ASTContext &C = S.getASTContext();
254 C.addTranslationUnitDecl();
255 LastPTU.TUPart = C.getTranslationUnitDecl();
256
257 // Skip previous eof due to last incremental input.
258 if (P->getCurToken().is(tok::annot_repl_input_end)) {
259 P->ConsumeAnyToken();
260 // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
261 // might want to do that around HandleEndOfTranslationUnit.
262 P->ExitScope();
263 S.CurContext = nullptr;
264 // Start a new PTU.
265 P->EnterScope(Scope::DeclScope);
266 S.ActOnTranslationUnitScope(P->getCurScope());
267 }
268
270 Sema::ModuleImportState ImportState;
271 for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
272 AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
273 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
274 return llvm::make_error<llvm::StringError>("Parsing failed. "
275 "The consumer rejected a decl",
276 std::error_code());
277 }
278
279 DiagnosticsEngine &Diags = getCI()->getDiagnostics();
280 if (Diags.hasErrorOccurred()) {
281 PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(),
282 nullptr};
283 CleanUpPTU(MostRecentPTU);
284
285 Diags.Reset(/*soft=*/true);
286 Diags.getClient()->clear();
287 return llvm::make_error<llvm::StringError>("Parsing failed.",
288 std::error_code());
289 }
290
291 // Process any TopLevelDecls generated by #pragma weak.
292 for (Decl *D : S.WeakTopLevelDecls()) {
293 DeclGroupRef DGR(D);
295 }
296
297 LocalInstantiations.perform();
298 GlobalInstantiations.perform();
299
301
302 return LastPTU;
303}
304
306IncrementalParser::Parse(llvm::StringRef input) {
307 Preprocessor &PP = CI->getPreprocessor();
308 assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
309
310 std::ostringstream SourceName;
311 SourceName << "input_line_" << InputCount++;
312
313 // Create an uninitialized memory buffer, copy code in and append "\n"
314 size_t InputSize = input.size(); // don't include trailing 0
315 // MemBuffer size should *not* include terminating zero
316 std::unique_ptr<llvm::MemoryBuffer> MB(
317 llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
318 SourceName.str()));
319 char *MBStart = const_cast<char *>(MB->getBufferStart());
320 memcpy(MBStart, input.data(), InputSize);
321 MBStart[InputSize] = '\n';
322
323 SourceManager &SM = CI->getSourceManager();
324
325 // FIXME: Create SourceLocation, which will allow clang to order the overload
326 // candidates for example
327 SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
328
329 // Create FileID for the current buffer.
330 FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
331 /*LoadedOffset=*/0, NewLoc);
332
333 // NewLoc only used for diags.
334 if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
335 return llvm::make_error<llvm::StringError>("Parsing failed. "
336 "Cannot enter source file.",
337 std::error_code());
338
339 auto PTU = ParseOrWrapTopLevelDecl();
340 if (!PTU)
341 return PTU.takeError();
342
343 if (PP.getLangOpts().DelayedTemplateParsing) {
344 // Microsoft-specific:
345 // Late parsed templates can leave unswallowed "macro"-like tokens.
346 // They will seriously confuse the Parser when entering the next
347 // source file. So lex until we are EOF.
348 Token Tok;
349 do {
350 PP.Lex(Tok);
351 } while (Tok.isNot(tok::annot_repl_input_end));
352 } else {
353 Token AssertTok;
354 PP.Lex(AssertTok);
355 assert(AssertTok.is(tok::annot_repl_input_end) &&
356 "Lexer must be EOF when starting incremental parse!");
357 }
358
359 if (std::unique_ptr<llvm::Module> M = GenModule())
360 PTU->TheModule = std::move(M);
361
362 return PTU;
363}
364
365std::unique_ptr<llvm::Module> IncrementalParser::GenModule() {
366 static unsigned ID = 0;
367 if (CodeGenerator *CG = getCodeGen()) {
368 // Clang's CodeGen is designed to work with a single llvm::Module. In many
369 // cases for convenience various CodeGen parts have a reference to the
370 // llvm::Module (TheModule or Module) which does not change when a new
371 // module is pushed. However, the execution engine wants to take ownership
372 // of the module which does not map well to CodeGen's design. To work this
373 // around we created an empty module to make CodeGen happy. We should make
374 // sure it always stays empty.
375 assert((!CachedInCodeGenModule ||
376 (CachedInCodeGenModule->empty() &&
377 CachedInCodeGenModule->global_empty() &&
378 CachedInCodeGenModule->alias_empty() &&
379 CachedInCodeGenModule->ifunc_empty())) &&
380 "CodeGen wrote to a readonly module");
381 std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
382 CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
383 return M;
384 }
385 return nullptr;
386}
387
389 TranslationUnitDecl *MostRecentTU = PTU.TUPart;
390 TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl();
391 if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) {
392 for (auto &&[Key, List] : *Map) {
393 DeclContextLookupResult R = List.getLookupResult();
394 std::vector<NamedDecl *> NamedDeclsToRemove;
395 bool RemoveAll = true;
396 for (NamedDecl *D : R) {
397 if (D->getTranslationUnitDecl() == MostRecentTU)
398 NamedDeclsToRemove.push_back(D);
399 else
400 RemoveAll = false;
401 }
402 if (LLVM_LIKELY(RemoveAll)) {
403 Map->erase(Key);
404 } else {
405 for (NamedDecl *D : NamedDeclsToRemove)
406 List.remove(D);
407 }
408 }
409 }
410}
411
414 assert(CG);
415 return CG->GetMangledName(GD);
416}
417} // end namespace clang
static char ID
Definition: Arena.cpp:183
#define SM(sm)
Definition: Cuda.cpp:82
Defines the clang::FrontendAction interface and various convenience abstract classes (clang::ASTFront...
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition: ASTConsumer.h:33
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition: ASTConsumer.h:66
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
Definition: ASTConsumer.cpp:18
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
An abstract interface that should be implemented by listeners that want to be notified when an AST en...
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
Abstract interface for a consumer of code-completion information.
The primary public interface to the Clang code generator.
Definition: ModuleBuilder.h:48
llvm::StringRef GetMangledName(GlobalDecl GD)
Given a global declaration, return a mangled name for this declaration which has been added to this c...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
bool hasCodeCompletionConsumer() const
CodeCompleteConsumer & getCodeCompletionConsumer() const
void createSema(TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer)
Create the Sema object to be used for parsing.
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1371
DeclContext * getPrimaryContext()
getPrimaryContext - There may be many different declarations of the same entity (including forward de...
Definition: DeclBase.cpp:1354
StoredDeclsMap * getLookupPtr() const
Retrieve the internal representation of the lookup structure.
Definition: DeclBase.h:2632
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Abstract base class for actions which can be performed by the frontend.
virtual bool hasIRSupport() const
Does this action support use with IR files?
CompilerInstance & getCompilerInstance() const
frontend::ActionKind ProgramAction
The frontend action to perform.
Represents a function declaration or definition.
Definition: Decl.h:1971
GlobalDecl - represents a global declaration.
Definition: GlobalDecl.h:56
Describes a module import declaration, which makes the contents of the named module visible in the cu...
Definition: Decl.h:4800
bool shouldSkipFunctionBody(Decl *D) override final
This callback is called for each function if the Parser was initialized with SkipFunctionBodies set t...
void HandleCXXStaticMemberVarInstantiation(VarDecl *D) override final
HandleCXXStaticMemberVarInstantiation - Tell the consumer that this.
void AssignInheritanceModel(CXXRecordDecl *RD) override final
Callback invoked when an MSInheritanceAttr has been attached to a CXXRecordDecl.
ASTDeserializationListener * GetASTDeserializationListener() override final
If the consumer is interested in entities being deserialized from AST files, it should return a point...
IncrementalASTConsumer(Interpreter &InterpRef, std::unique_ptr< ASTConsumer > C)
void HandleVTable(CXXRecordDecl *RD) override final
Callback involved at the end of a translation unit to notify the consumer that a vtable for the given...
void CompleteExternalDeclaration(VarDecl *D) override final
CompleteExternalDeclaration - Callback invoked at the end of a translation unit to notify the consume...
void HandleTagDeclDefinition(TagDecl *D) override final
HandleTagDeclDefinition - This callback is invoked each time a TagDecl (e.g.
void HandleInterestingDecl(DeclGroupRef D) override final
HandleInterestingDecl - Handle the specified interesting declaration.
void HandleImplicitImportDecl(ImportDecl *D) override final
Handle an ImportDecl that was implicitly created due to an inclusion directive.
ASTMutationListener * GetASTMutationListener() override final
If the consumer is interested in entities getting modified after their initial creation,...
bool HandleTopLevelDecl(DeclGroupRef DGR) override final
HandleTopLevelDecl - Handle the specified top-level declaration.
void PrintStats() override final
PrintStats - If desired, print any statistics.
static bool classof(const clang::ASTConsumer *)
void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override final
Invoked when a function is implicitly instantiated.
void HandleInlineFunctionDefinition(FunctionDecl *D) override final
This callback is invoked each time an inline (method or friend) function definition in a class is com...
void HandleTagDeclRequiredDefinition(const TagDecl *D) override final
This callback is invoked the first time each TagDecl is required to be complete.
void CompleteTentativeDefinition(VarDecl *D) override final
CompleteTentativeDefinition - Callback invoked at the end of a translation unit to notify the consume...
void HandleTranslationUnit(ASTContext &Ctx) override final
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override final
Handle the specified top-level declaration that occurred inside and ObjC container.
A custom action enabling the incremental processing functionality.
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
TranslationUnitKind getTranslationUnitKind() override
For AST-based actions, the kind of translation unit we're handling.
IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx, llvm::Error &Err)
FrontendAction * getWrapped() const
void EndSourceFile() override
Perform any per-file post processing, deallocate per-file objects, and run statistics and output file...
std::list< PartialTranslationUnit > PTUs
List containing every information about every incrementally parsed piece of code.
llvm::StringRef GetMangledName(GlobalDecl GD) const
Uses the CodeGenModule mangled name cache and avoids recomputing.
std::unique_ptr< IncrementalAction > Act
Long-lived, incremental parsing action.
virtual llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Input)
Parses incremental input by creating an in-memory file.
CompilerInstance * getCI()
std::unique_ptr< CompilerInstance > CI
Compiler instance performing the incremental compilation.
void CleanUpPTU(PartialTranslationUnit &PTU)
unsigned InputCount
Counts the number of direct user input lines that have been parsed.
std::unique_ptr< llvm::Module > GenModule()
std::unique_ptr< llvm::Module > CachedInCodeGenModule
When CodeGen is created the first llvm::Module gets cached in many places and we must keep it alive.
std::unique_ptr< Parser > P
Parser.
ASTConsumer * Consumer
Consumer to process the produced top level decls. Owned by Act.
CodeGenerator * getCodeGen() const
Provides top-level interfaces for incremental compilation and execution.
Definition: Interpreter.h:91
This represents a decl that may have a name.
Definition: Decl.h:249
Parser - This implements a parser for the C family of languages.
Definition: Parser.h:56
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
Definition: Parser.h:505
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
bool isIncrementalProcessingEnabled() const
Returns true if incremental processing is enabled.
void Lex(Token &Result)
Lex the next token for this preprocessor.
bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir, SourceLocation Loc, bool IsFirstIncludeOfFile=true)
Add a source file to the top of the include stack and start lexing tokens from it instead of the curr...
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc.
const LangOptions & getLangOpts() const
decl_type * getFirstDecl()
Return the first declaration of this declaration or itself if this is the only declaration.
Definition: Redeclarable.h:216
@ DeclScope
This is a scope that can contain a declaration.
Definition: Scope.h:63
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:457
ModuleImportState
An enumeration to represent the transition of states in parsing module fragments and imports.
Definition: Sema.h:7766
Encodes a location in the source.
This class handles loading and caching of source files into memory.
Represents the declaration of a struct/union/class/enum.
Definition: Decl.h:3585
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....
Definition: Token.h:99
bool isNot(tok::TokenKind K) const
Definition: Token.h:100
The top declaration context.
Definition: Decl.h:84
Represents a variable declaration or definition.
Definition: Decl.h:918
A frontend action which simply wraps some other runtime-specified frontend action.
std::unique_ptr< FrontendAction > WrappedAction
void EndSourceFile() override
Perform any per-file post processing, deallocate per-file objects, and run statistics and output file...
@ PrintPreprocessedInput
-E mode.
@ ParseSyntaxOnly
Parse and perform semantic analysis.
@ EmitBC
Emit a .bc file.
@ PluginAction
Run a plugin action,.
@ EmitObj
Emit a .o file.
@ ASTPrint
Parse ASTs and print them.
@ ASTDump
Parse ASTs and dump them.
@ EmitAssembly
Emit a .s file.
@ EmitLLVMOnly
Generate LLVM IR, but do not emit anything.
The JSON file list parser is used to communicate input to InstallAPI.
std::unique_ptr< FrontendAction > CreateFrontendAction(CompilerInstance &CI)
Construct the FrontendAction of a compiler invocation based on the options specified for the compiler...
TranslationUnitKind
Describes the kind of translation unit being processed.
Definition: LangOptions.h:1029
@ TU_Incremental
The translation unit is a is a complete translation unit that we might incrementally extend later.
Definition: LangOptions.h:1042
Definition: Format.h:5394
The class keeps track of various objects created as part of processing incremental inputs.