#include "ParsedAST.h"
#include "../clang-tidy/ClangTidyCheck.h"
#include "../clang-tidy/ClangTidyDiagnosticConsumer.h"
#include "../clang-tidy/ClangTidyModule.h"
#include "../clang-tidy/ClangTidyModuleRegistry.h"
#include "../clang-tidy/ClangTidyOptions.h"
#include "AST.h"
#include "CollectMacros.h"
#include "Compiler.h"
#include "Config.h"
#include "Diagnostics.h"
#include "Feature.h"
#include "FeatureModule.h"
#include "Headers.h"
#include "HeuristicResolver.h"
#include "IncludeCleaner.h"
#include "IncludeFixer.h"
#include "Preamble.h"
#include "SourceCode.h"
#include "TidyProvider.h"
#include "clang-include-cleaner/Record.h"
#include "index/Symbol.h"
#include "support/Logger.h"
#include "support/Path.h"
#include "support/Trace.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/FileEntry.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/PrecompiledPreamble.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/Core/Diagnostic.h"
#include "clang/Tooling/Syntax/Tokens.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cassert>
#include <cstddef>
#include <iterator>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#if CLANGD_TIDY_CHECKS
#define CLANG_TIDY_DISABLE_STATIC_ANALYZER_CHECKS
#include "../clang-tidy/ClangTidyForceLinker.h"
#endif
namespace clang {
namespace clangd {
namespace {
template <class T> std::size_t getUsedBytes(const std::vector<T> &Vec) {
return Vec.capacity() * sizeof(T);
}
class DeclTrackingASTConsumer : public ASTConsumer {
public:
DeclTrackingASTConsumer(std::vector<Decl *> &TopLevelDecls)
: TopLevelDecls(TopLevelDecls) {}
bool HandleTopLevelDecl(DeclGroupRef DG) override {
for (Decl *D : DG) {
auto &SM = D->getASTContext().getSourceManager();
if (!isInsideMainFile(D->getLocation(), SM))
continue;
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
if (isImplicitTemplateInstantiation(ND))
continue;
if (isa<ObjCMethodDecl>(D))
continue;
TopLevelDecls.push_back(D);
}
return true;
}
private:
std::vector<Decl *> &TopLevelDecls;
};
class ClangdFrontendAction : public SyntaxOnlyAction {
public:
std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
protected:
std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
return std::make_unique<DeclTrackingASTConsumer>( TopLevelDecls);
}
private:
std::vector<Decl *> TopLevelDecls;
};
class ReplayPreamble : private PPCallbacks {
public:
static void attach(std::vector<Inclusion> Includes, CompilerInstance &Clang,
const PreambleBounds &PB) {
auto &PP = Clang.getPreprocessor();
auto *ExistingCallbacks = PP.getPPCallbacks();
if (!ExistingCallbacks)
return;
PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(new ReplayPreamble(
std::move(Includes), ExistingCallbacks, Clang.getSourceManager(), PP,
Clang.getLangOpts(), PB)));
assert(PP.getPPCallbacks() != ExistingCallbacks &&
"Expected chaining implementation");
}
private:
ReplayPreamble(std::vector<Inclusion> Includes, PPCallbacks *Delegate,
const SourceManager &SM, Preprocessor &PP,
const LangOptions &LangOpts, const PreambleBounds &PB)
: Includes(std::move(Includes)), Delegate(Delegate), SM(SM), PP(PP) {
MainFileTokens = syntax::tokenize(
syntax::FileRange(SM.getMainFileID(), 0, PB.Size), SM, LangOpts);
}
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind Kind, FileID PrevFID) override {
if (Reason == FileChangeReason::ExitFile &&
SM.getBufferOrFake(PrevFID).getBufferIdentifier() == "<built-in>")
replay();
}
void replay() {
for (const auto &Inc : Includes) {
OptionalFileEntryRef File;
if (Inc.Resolved != "")
File = expectedToOptional(SM.getFileManager().getFileRef(Inc.Resolved));
auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);
auto HashTok = llvm::partition_point(MainFileTokens,
[&HashLoc](const syntax::Token &T) {
return T.location() < HashLoc;
});
assert(HashTok != MainFileTokens.end() && HashTok->kind() == tok::hash);
auto IncludeTok = std::next(HashTok);
assert(IncludeTok != MainFileTokens.end());
auto FileTok = std::next(IncludeTok);
assert(FileTok != MainFileTokens.end());
Token SynthesizedIncludeTok;
SynthesizedIncludeTok.startToken();
SynthesizedIncludeTok.setLocation(IncludeTok->location());
SynthesizedIncludeTok.setLength(IncludeTok->length());
SynthesizedIncludeTok.setKind(tok::raw_identifier);
SynthesizedIncludeTok.setRawIdentifierData(IncludeTok->text(SM).data());
PP.LookUpIdentifierInfo(SynthesizedIncludeTok);
Token SynthesizedFilenameTok;
SynthesizedFilenameTok.startToken();
SynthesizedFilenameTok.setLocation(FileTok->location());
SynthesizedFilenameTok.setLength(Inc.Written.length());
SynthesizedFilenameTok.setKind(tok::header_name);
SynthesizedFilenameTok.setLiteralData(Inc.Written.data());
llvm::StringRef WrittenFilename =
llvm::StringRef(Inc.Written).drop_front().drop_back();
Delegate->InclusionDirective(
HashTok->location(), SynthesizedIncludeTok, WrittenFilename,
Inc.Written.front() == '<',
syntax::FileRange(SM, SynthesizedFilenameTok.getLocation(),
SynthesizedFilenameTok.getEndLoc())
.toCharRange(SM),
File, "SearchPath", "RelPath",
nullptr, false, Inc.FileKind);
if (File)
Delegate->FileSkipped(*File, SynthesizedFilenameTok, Inc.FileKind);
}
}
const std::vector<Inclusion> Includes;
PPCallbacks *Delegate;
const SourceManager &SM;
Preprocessor &PP;
std::vector<syntax::Token> MainFileTokens;
};
class TidyDiagnosticGroups {
bool Default = false;
llvm::DenseSet<unsigned> Exceptions;
public:
TidyDiagnosticGroups(llvm::StringRef Checks) {
constexpr llvm::StringLiteral CDPrefix = "clang-diagnostic-";
llvm::StringRef Check;
while (!Checks.empty()) {
std::tie(Check, Checks) = Checks.split(',');
if (Check.empty())
continue;
bool Enable = !Check.consume_front("-");
bool Glob = Check.consume_back("*");
if (Glob) {
if (CDPrefix.starts_with(Check)) {
Default = Enable;
Exceptions.clear();
}
continue;
}
if (Default == Enable)
continue;
if (!Check.consume_front(CDPrefix))
continue;
if (auto Group = DiagnosticIDs::getGroupForWarningOption(Check))
Exceptions.insert(static_cast<unsigned>(*Group));
}
}
bool operator()(diag::Group GroupID) const {
return Exceptions.contains(static_cast<unsigned>(GroupID)) ? !Default
: Default;
}
};
void applyWarningOptions(llvm::ArrayRef<std::string> ExtraArgs,
llvm::function_ref<bool(diag::Group)> EnabledGroups,
DiagnosticsEngine &Diags) {
for (llvm::StringRef Group : ExtraArgs) {
llvm::SmallVector<diag::kind> Members;
if (!Group.consume_front("-W") || Group.empty())
continue;
bool Enable = !Group.consume_front("no-");
if (Diags.getDiagnosticIDs()->getDiagnosticsInGroup(
diag::Flavor::WarningOrError, Group, Members))
continue;
bool NeedsWerrorExclusion = false;
for (diag::kind ID : Members) {
if (Enable) {
if (Diags.getDiagnosticLevel(ID, SourceLocation()) <
DiagnosticsEngine::Warning) {
auto Group = DiagnosticIDs::getGroupForDiag(ID);
if (!Group || !EnabledGroups(*Group))
continue;
Diags.setSeverity(ID, diag::Severity::Warning, SourceLocation());
if (Diags.getWarningsAsErrors())
NeedsWerrorExclusion = true;
}
} else {
Diags.setSeverity(ID, diag::Severity::Ignored, SourceLocation());
}
}
if (NeedsWerrorExclusion) {
Diags.setDiagnosticGroupWarningAsError(Group, false);
}
}
}
std::vector<Diag> getIncludeCleanerDiags(ParsedAST &AST, llvm::StringRef Code,
const ThreadsafeFS &TFS) {
auto &Cfg = Config::current();
if (Cfg.Diagnostics.SuppressAll)
return {};
bool SuppressMissing =
Cfg.Diagnostics.Suppress.contains("missing-includes") ||
Cfg.Diagnostics.MissingIncludes == Config::IncludesPolicy::None;
bool SuppressUnused =
Cfg.Diagnostics.Suppress.contains("unused-includes") ||
Cfg.Diagnostics.UnusedIncludes == Config::IncludesPolicy::None;
if (SuppressMissing && SuppressUnused)
return {};
auto Findings = computeIncludeCleanerFindings(
AST, Cfg.Diagnostics.Includes.AnalyzeAngledIncludes);
if (SuppressMissing)
Findings.MissingIncludes.clear();
if (SuppressUnused)
Findings.UnusedIncludes.clear();
return issueIncludeCleanerDiagnostics(AST, Code, Findings, TFS,
Cfg.Diagnostics.Includes.IgnoreHeader);
}
tidy::ClangTidyCheckFactories
filterFastTidyChecks(const tidy::ClangTidyCheckFactories &All,
Config::FastCheckPolicy Policy) {
if (Policy == Config::FastCheckPolicy::None)
return All;
bool AllowUnknown = Policy == Config::FastCheckPolicy::Loose;
tidy::ClangTidyCheckFactories Fast;
for (const auto &Factory : All) {
if (isFastTidyCheck(Factory.getKey()).value_or(AllowUnknown))
Fast.registerCheckFactory(Factory.first(), Factory.second);
}
return Fast;
}
}
std::optional<ParsedAST>
ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
std::unique_ptr<clang::CompilerInvocation> CI,
llvm::ArrayRef<Diag> CompilerInvocationDiags,
std::shared_ptr<const PreambleData> Preamble) {
trace::Span Tracer("BuildAST");
SPAN_ATTACH(Tracer, "File", Filename);
const Config &Cfg = Config::current();
auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
if (Preamble && Preamble->StatCache)
VFS = Preamble->StatCache->getConsumingFS(std::move(VFS));
assert(CI);
if (CI->getFrontendOpts().Inputs.size() > 0) {
auto Lang = CI->getFrontendOpts().Inputs[0].getKind().getLanguage();
if (Lang == Language::Asm || Lang == Language::LLVM_IR) {
elog("Clangd does not support assembly or IR source files");
return std::nullopt;
}
}
CI->getFrontendOpts().DisableFree = false;
const PrecompiledPreamble *PreamblePCH =
Preamble ? &Preamble->Preamble : nullptr;
CI->getLangOpts().DelayedTemplateParsing = false;
std::vector<std::unique_ptr<FeatureModule::ASTListener>> ASTListeners;
if (Inputs.FeatureModules) {
for (auto &M : *Inputs.FeatureModules) {
if (auto Listener = M.astListeners())
ASTListeners.emplace_back(std::move(Listener));
}
}
StoreDiags ASTDiags;
ASTDiags.setDiagCallback(
[&ASTListeners](const clang::Diagnostic &D, clangd::Diag &Diag) {
for (const auto &L : ASTListeners)
L->sawDiagnostic(D, Diag);
});
if (Preamble && Preamble->RequiredModules)
Preamble->RequiredModules->adjustHeaderSearchOptions(
CI->getHeaderSearchOpts());
std::optional<PreamblePatch> Patch;
DiagnosticConsumer *DiagConsumer = &ASTDiags;
IgnoreDiagnostics DropDiags;
if (Preamble) {
Patch = PreamblePatch::createFullPatch(Filename, Inputs, *Preamble);
Patch->apply(*CI);
}
auto Clang = prepareCompilerInstance(
std::move(CI), PreamblePCH,
llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, Filename), VFS,
*DiagConsumer);
if (!Clang) {
std::vector<Diag> Diags(ASTDiags.take());
elog("Failed to prepare a compiler instance: {0}",
!Diags.empty() ? static_cast<DiagBase &>(Diags.back()).Message
: "unknown error");
return std::nullopt;
}
tidy::ClangTidyOptions ClangTidyOpts;
{
trace::Span Tracer("ClangTidyOpts");
ClangTidyOpts = getTidyOptionsForFile(Inputs.ClangTidyProvider, Filename);
dlog("ClangTidy configuration for file {0}: {1}", Filename,
tidy::configurationAsText(ClangTidyOpts));
auto &Diags = Clang->getDiagnostics();
TidyDiagnosticGroups TidyGroups(ClangTidyOpts.Checks ? *ClangTidyOpts.Checks
: llvm::StringRef());
if (ClangTidyOpts.ExtraArgsBefore)
applyWarningOptions(*ClangTidyOpts.ExtraArgsBefore, TidyGroups, Diags);
if (ClangTidyOpts.ExtraArgs)
applyWarningOptions(*ClangTidyOpts.ExtraArgs, TidyGroups, Diags);
}
auto Action = std::make_unique<ClangdFrontendAction>();
const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
if (!Action->BeginSourceFile(*Clang, MainInput)) {
log("BeginSourceFile() failed when building AST for {0}",
MainInput.getFile());
return std::nullopt;
}
if (Preamble && Preamble->MainIsIncludeGuarded) {
const SourceManager &SM = Clang->getSourceManager();
OptionalFileEntryRef MainFE = SM.getFileEntryRefForID(SM.getMainFileID());
Clang->getPreprocessor().getHeaderSearchInfo().MarkFileIncludeOnce(*MainFE);
}
std::vector<std::unique_ptr<tidy::ClangTidyCheck>> CTChecks;
ast_matchers::MatchFinder CTFinder;
std::optional<tidy::ClangTidyContext> CTContext;
auto BuildDir = VFS->getCurrentWorkingDirectory();
std::optional<IncludeFixer> FixIncludes;
llvm::DenseMap<diag::kind, DiagnosticsEngine::Level> OverriddenSeverity;
{
trace::Span Tracer("ClangTidyInit");
static const auto *AllCTFactories = [] {
auto *CTFactories = new tidy::ClangTidyCheckFactories;
for (const auto &E : tidy::ClangTidyModuleRegistry::entries())
E.instantiate()->addCheckFactories(*CTFactories);
return CTFactories;
}();
tidy::ClangTidyCheckFactories FastFactories = filterFastTidyChecks(
*AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
CTContext->setASTContext(&Clang->getASTContext());
CTContext->setCurrentFile(Filename);
CTContext->setSelfContainedDiags(true);
CTChecks = FastFactories.createChecksForLanguage(&*CTContext);
Preprocessor *PP = &Clang->getPreprocessor();
for (const auto &Check : CTChecks) {
Check->registerPPCallbacks(Clang->getSourceManager(), PP, PP);
Check->registerMatchers(&CTFinder);
}
for (auto ID : {diag::ext_implicit_function_decl_c99,
diag::ext_implicit_lib_function_decl,
diag::ext_implicit_lib_function_decl_c99,
diag::warn_implicit_function_decl}) {
OverriddenSeverity.try_emplace(
ID, Clang->getDiagnostics().getDiagnosticLevel(ID, SourceLocation()));
Clang->getDiagnostics().setSeverity(ID, diag::Severity::Error,
SourceLocation());
}
ASTDiags.setLevelAdjuster([&](DiagnosticsEngine::Level DiagLevel,
const clang::Diagnostic &Info) {
if (Cfg.Diagnostics.SuppressAll ||
isBuiltinDiagnosticSuppressed(Info.getID(), Cfg.Diagnostics.Suppress,
Clang->getLangOpts()))
return DiagnosticsEngine::Ignored;
auto It = OverriddenSeverity.find(Info.getID());
if (It != OverriddenSeverity.end())
DiagLevel = It->second;
if (!CTChecks.empty()) {
std::string CheckName = CTContext->getCheckName(Info.getID());
bool IsClangTidyDiag = !CheckName.empty();
if (IsClangTidyDiag) {
if (Cfg.Diagnostics.Suppress.contains(CheckName))
return DiagnosticsEngine::Ignored;
bool IsInsideMainFile =
Info.hasSourceManager() &&
isInsideMainFile(Info.getLocation(), Info.getSourceManager());
SmallVector<tooling::Diagnostic, 1> TidySuppressedErrors;
if (IsInsideMainFile && CTContext->shouldSuppressDiagnostic(
DiagLevel, Info, TidySuppressedErrors,
false,
true)) {
return DiagnosticsEngine::Ignored;
}
if (!CTContext->getOptions().SystemHeaders.value_or(false) &&
Info.hasSourceManager() &&
Info.getSourceManager().isInSystemMacro(Info.getLocation()))
return DiagnosticsEngine::Ignored;
if (DiagLevel == DiagnosticsEngine::Warning &&
CTContext->treatAsError(CheckName)) {
return DiagnosticsEngine::Error;
}
}
}
return DiagLevel;
});
if (Inputs.Index && !BuildDir.getError()) {
auto Style =
getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.TFS, false);
auto Inserter = std::make_shared<IncludeInserter>(
Filename, Inputs.Contents, Style, BuildDir.get(),
&Clang->getPreprocessor().getHeaderSearchInfo());
ArrayRef<Inclusion> MainFileIncludes;
if (Preamble) {
MainFileIncludes = Preamble->Includes.MainFileIncludes;
for (const auto &Inc : Preamble->Includes.MainFileIncludes)
Inserter->addExisting(Inc);
}
Symbol::IncludeDirective Directive =
Inputs.Opts.ImportInsertions
? preferredIncludeDirective(Filename, Clang->getLangOpts(),
MainFileIncludes, {})
: Symbol::Include;
FixIncludes.emplace(Filename, Inserter, *Inputs.Index,
5, Directive);
ASTDiags.contributeFixes([&FixIncludes](DiagnosticsEngine::Level DiagLevl,
const clang::Diagnostic &Info) {
return FixIncludes->fix(DiagLevl, Info);
});
Clang->setExternalSemaSource(FixIncludes->unresolvedNameRecorder());
}
}
IncludeStructure Includes;
include_cleaner::PragmaIncludes PI;
if (Preamble) {
Includes = Preamble->Includes;
Includes.MainFileIncludes = Patch->preambleIncludes();
ReplayPreamble::attach(Patch->preambleIncludes(), *Clang,
Patch->modifiedBounds());
PI = *Preamble->Pragmas;
}
Includes.collect(*Clang);
PI.record(*Clang);
MainFileMacros Macros;
std::vector<PragmaMark> Marks;
if (Preamble) {
Macros = Patch->mainFileMacros();
Marks = Patch->marks();
}
auto &PP = Clang->getPreprocessor();
PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, Macros));
PP.addPPCallbacks(
collectPragmaMarksCallback(Clang->getSourceManager(), Marks));
syntax::TokenCollector CollectTokens(PP);
for (const auto &L : ASTListeners)
L->beforeExecute(*Clang);
if (llvm::Error Err = Action->Execute())
log("Execute() failed when building AST for {0}: {1}", MainInput.getFile(),
toString(std::move(Err)));
syntax::TokenBuffer Tokens = std::move(CollectTokens).consume();
Tokens.indexExpandedTokens();
std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls();
Clang->getASTContext().setTraversalScope(ParsedDecls);
if (!CTChecks.empty()) {
trace::Span Tracer("ClangTidyMatch");
CTFinder.matchAST(Clang->getASTContext());
}
PP.EndSourceFile();
Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
ASTDiags.EndSourceFile();
std::vector<Diag> Diags = CompilerInvocationDiags;
if (Preamble)
llvm::append_range(Diags, Patch->patchedDiags());
{
std::vector<Diag> D = ASTDiags.take(&*CTContext);
Diags.insert(Diags.end(), D.begin(), D.end());
}
ParsedAST Result(Filename, Inputs.Version, std::move(Preamble),
std::move(Clang), std::move(Action), std::move(Tokens),
std::move(Macros), std::move(Marks), std::move(ParsedDecls),
std::move(Diags), std::move(Includes), std::move(PI));
llvm::move(getIncludeCleanerDiags(Result, Inputs.Contents, *Inputs.TFS),
std::back_inserter(Result.Diags));
return std::move(Result);
}
ParsedAST::ParsedAST(ParsedAST &&Other) = default;
ParsedAST &ParsedAST::operator=(ParsedAST &&Other) = default;
ParsedAST::~ParsedAST() {
if (Action) {
auto PP = Clang->getPreprocessorPtr();
Clang->setPreprocessor(nullptr);
Action->EndSourceFile();
}
}
ASTContext &ParsedAST::getASTContext() { return Clang->getASTContext(); }
const ASTContext &ParsedAST::getASTContext() const {
return Clang->getASTContext();
}
Sema &ParsedAST::getSema() { return Clang->getSema(); }
Preprocessor &ParsedAST::getPreprocessor() { return Clang->getPreprocessor(); }
std::shared_ptr<Preprocessor> ParsedAST::getPreprocessorPtr() {
return Clang->getPreprocessorPtr();
}
const Preprocessor &ParsedAST::getPreprocessor() const {
return Clang->getPreprocessor();
}
llvm::ArrayRef<Decl *> ParsedAST::getLocalTopLevelDecls() {
return LocalTopLevelDecls;
}
llvm::ArrayRef<const Decl *> ParsedAST::getLocalTopLevelDecls() const {
return LocalTopLevelDecls;
}
const MainFileMacros &ParsedAST::getMacros() const { return Macros; }
const std::vector<PragmaMark> &ParsedAST::getMarks() const { return Marks; }
std::size_t ParsedAST::getUsedBytes() const {
auto &AST = getASTContext();
std::size_t Total =
clangd::getUsedBytes(LocalTopLevelDecls) + clangd::getUsedBytes(Diags);
Total += AST.getASTAllocatedMemory();
Total += AST.getSideTableAllocatedMemory();
Total += AST.Idents.getAllocator().getTotalMemory();
Total += AST.Selectors.getTotalMemory();
Total += AST.getSourceManager().getContentCacheSize();
Total += AST.getSourceManager().getDataStructureSizes();
Total += AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
if (ExternalASTSource *Ext = AST.getExternalSource())
Total += Ext->getMemoryBufferSizes().malloc_bytes;
const Preprocessor &PP = getPreprocessor();
Total += PP.getTotalMemory();
if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
Total += PRec->getTotalMemory();
Total += PP.getHeaderSearchInfo().getTotalMemory();
return Total;
}
const IncludeStructure &ParsedAST::getIncludeStructure() const {
return Includes;
}
ParsedAST::ParsedAST(PathRef TUPath, llvm::StringRef Version,
std::shared_ptr<const PreambleData> Preamble,
std::unique_ptr<CompilerInstance> Clang,
std::unique_ptr<FrontendAction> Action,
syntax::TokenBuffer Tokens, MainFileMacros Macros,
std::vector<PragmaMark> Marks,
std::vector<Decl *> LocalTopLevelDecls,
std::vector<Diag> Diags, IncludeStructure Includes,
include_cleaner::PragmaIncludes PI)
: TUPath(TUPath), Version(Version), Preamble(std::move(Preamble)),
Clang(std::move(Clang)), Action(std::move(Action)),
Tokens(std::move(Tokens)), Macros(std::move(Macros)),
Marks(std::move(Marks)), Diags(std::move(Diags)),
LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
Includes(std::move(Includes)), PI(std::move(PI)),
Resolver(std::make_unique<HeuristicResolver>(getASTContext())) {
assert(this->Clang);
assert(this->Action);
}
const include_cleaner::PragmaIncludes &ParsedAST::getPragmaIncludes() const {
return PI;
}
std::optional<llvm::StringRef> ParsedAST::preambleVersion() const {
if (!Preamble)
return std::nullopt;
return llvm::StringRef(Preamble->Version);
}
llvm::ArrayRef<Diag> ParsedAST::getDiagnostics() const { return Diags; }
}
}