2015-10-07 07:40:43 +08:00
|
|
|
//===--- ASTUnit.cpp - ASTUnit utility --------------------------*- C++ -*-===//
|
2009-06-20 16:27:14 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// ASTUnit Implementation.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/Frontend/ASTUnit.h"
|
2009-12-01 17:51:01 +08:00
|
|
|
#include "clang/AST/ASTConsumer.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/AST/DeclVisitor.h"
|
|
|
|
#include "clang/AST/StmtVisitor.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/AST/TypeOrdering.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
Reapply "Modules: Cache PCMs in memory and avoid a use-after-free"
This reverts commit r298185, effectively reapplying r298165, after fixing the
new unit tests (PR32338). The memory buffer generator doesn't null-terminate
the MemoryBuffer it creates; this version of the commit informs getMemBuffer
about that to avoid the assert.
Original commit message follows:
----
Clang's internal build system for implicit modules uses lock files to
ensure that after a process writes a PCM it will read the same one back
in (without contention from other -cc1 commands). Since PCMs are read
from disk repeatedly while invalidating, building, and importing, the
lock is not released quickly. Furthermore, the LockFileManager is not
robust in every environment. Other -cc1 commands can stall until
timeout (after about eight minutes).
This commit changes the lock file from being necessary for correctness
to a (possibly dubious) performance hack. The remaining benefit is to
reduce duplicate work in competing -cc1 commands which depend on the
same module. Follow-up commits will change the internal build system to
continue after a timeout, and reduce the timeout. Perhaps we should
reconsider blocking at all.
This also fixes a use-after-free, when one part of a compilation
validates a PCM and starts using it, and another tries to swap out the
PCM for something new.
The PCMCache is a new type called MemoryBufferCache, which saves memory
buffers based on their filename. Its ownership is shared by the
CompilerInstance and ModuleManager.
- The ModuleManager stores PCMs there that it loads from disk, never
touching the disk if the cache is hot.
- When modules fail to validate, they're removed from the cache.
- When a CompilerInstance is spawned to build a new module, each
already-loaded PCM is assumed to be valid, and is frozen to avoid
the use-after-free.
- Any newly-built module is written directly to the cache to avoid the
round-trip to the filesystem, making lock files unnecessary for
correctness.
Original patch by Manman Ren; most testcases by Adrian Prantl!
llvm-svn: 298278
2017-03-21 01:58:26 +08:00
|
|
|
#include "clang/Basic/MemoryBufferCache.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
|
|
|
#include "clang/Basic/TargetOptions.h"
|
2014-02-21 05:59:23 +08:00
|
|
|
#include "clang/Basic/VirtualFileSystem.h"
|
2009-12-01 17:51:01 +08:00
|
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
|
|
#include "clang/Frontend/FrontendActions.h"
|
2009-12-02 11:23:45 +08:00
|
|
|
#include "clang/Frontend/FrontendDiagnostic.h"
|
2009-12-01 17:51:01 +08:00
|
|
|
#include "clang/Frontend/FrontendOptions.h"
|
2011-11-28 12:56:00 +08:00
|
|
|
#include "clang/Frontend/MultiplexConsumer.h"
|
2010-10-12 05:37:58 +08:00
|
|
|
#include "clang/Frontend/Utils.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2012-10-25 01:46:57 +08:00
|
|
|
#include "clang/Lex/PreprocessorOptions.h"
|
Remove unnecessary inclusion of Sema.h
Let me tell you a tale...
Within some twisted maze of debug info I've ended up implementing an
insane man's Include What You Use device. When the debugger emits debug
info it really shouldn't, I find out why & then realize the code could
be improved too.
In this instance CIndexDiagnostics.cpp had a lot more debug info with
Clang than GCC. Upon inspection a major culprit was all the debug info
describing clang::Sema. This was emitted because clang::Sema is
befriended by DiagnosticEngine which was rightly required, but GCC
doesn't emit debug info for friends so it never emitted anything for
Clang. Clang does emit debug info for friends (will be fixed/changed to
reduce debug info size).
But why didn't Clang just emit a declaration of Sema if this entire TU
didn't require a definition?
1) Diagnostic.h did the right thing, only using a declaration of Sema
and not including Sema.h at all.
2) Some other dependency of CIndexDiagnostics.cpp didn't do the right
thing. ASTUnit.h, only needing a declaration, still included Sema.h
(hence this commit which removes that include and adds the necessary
includes to the cpp files that were relying on this)
3) -flimit-debug-info didn't save us because of
EnterExpressionEvaluationContext, defined inline in Sema.h which fires
the "requiresCompleteType" check/flag (since it uses nested types from
Sema and calls Sema member functions) and thus, if debug info is ever
emitted for the type, the whole type is emitted and not just a
declaration.
Improving -flimit-debug-info to account for this would be... hard.
Modifying the code so that's not 'required to be complete' might be
possible, but probably only by moving EnterExpressionEvaluationContext
either into Sema, or out of Sema.h. That might be a bit too much of a
contortion to be bothered with.
Also, this is only one of the cases where emitting debug info for
friends caused us to emit a lot more debug info (this change reduces
Clang's DWO size by 0.93%, dropping friends entirely reduces debug info
by 3.2%) - I haven't hunted down the other cases, but I assume they
might be similar (Sema or something like it). IWYU or a similar tool
might help us reduce build times a bit, but analyzing debug info to find
these differences isn't worthwhile. I'll take the 3.2% win, provide this
small improvement to the code itself, and move on.
llvm-svn: 190715
2013-09-14 02:32:52 +08:00
|
|
|
#include "clang/Sema/Sema.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Serialization/ASTReader.h"
|
|
|
|
#include "clang/Serialization/ASTWriter.h"
|
2011-03-23 12:04:01 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2010-08-17 07:08:34 +08:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/Support/CrashRecoveryContext.h"
|
2018-02-26 23:16:42 +08:00
|
|
|
#include "llvm/Support/DJB.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/Support/Host.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2011-10-11 05:57:12 +08:00
|
|
|
#include "llvm/Support/Mutex.h"
|
2011-10-28 03:44:25 +08:00
|
|
|
#include "llvm/Support/MutexGuard.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/Support/Timer.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2014-03-03 01:08:31 +08:00
|
|
|
#include <atomic>
|
2010-07-23 10:15:08 +08:00
|
|
|
#include <cstdio>
|
2012-12-04 17:13:33 +08:00
|
|
|
#include <cstdlib>
|
2015-10-07 07:40:43 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
using llvm::TimeRecord;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class SimpleTimer {
|
|
|
|
bool WantTiming;
|
|
|
|
TimeRecord Start;
|
|
|
|
std::string Output;
|
|
|
|
|
2010-11-10 04:00:56 +08:00
|
|
|
public:
|
2010-11-01 21:48:43 +08:00
|
|
|
explicit SimpleTimer(bool WantTiming) : WantTiming(WantTiming) {
|
2010-10-28 23:44:59 +08:00
|
|
|
if (WantTiming)
|
2010-11-10 04:00:56 +08:00
|
|
|
Start = TimeRecord::getCurrentTime();
|
2010-10-28 23:44:59 +08:00
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void setOutput(const Twine &Output) {
|
2010-10-28 23:44:59 +08:00
|
|
|
if (WantTiming)
|
2010-11-10 04:00:56 +08:00
|
|
|
this->Output = Output.str();
|
2010-10-28 23:44:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
~SimpleTimer() {
|
|
|
|
if (WantTiming) {
|
|
|
|
TimeRecord Elapsed = TimeRecord::getCurrentTime();
|
|
|
|
Elapsed -= Start;
|
|
|
|
llvm::errs() << Output << ':';
|
|
|
|
Elapsed.print(Elapsed, llvm::errs());
|
|
|
|
llvm::errs() << '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2017-05-23 19:37:52 +08:00
|
|
|
|
|
|
|
template <class T>
|
|
|
|
std::unique_ptr<T> valueOrNull(llvm::ErrorOr<std::unique_ptr<T>> Val) {
|
|
|
|
if (!Val)
|
|
|
|
return nullptr;
|
|
|
|
return std::move(*Val);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
|
|
|
|
if (!Val)
|
|
|
|
return false;
|
|
|
|
Output = std::move(*Val);
|
|
|
|
return true;
|
|
|
|
}
|
2011-10-28 01:55:18 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
/// \brief Get a source buffer for \p MainFilePath, handling all file-to-file
|
|
|
|
/// and file-to-buffer remappings inside \p Invocation.
|
|
|
|
static std::unique_ptr<llvm::MemoryBuffer>
|
|
|
|
getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation,
|
|
|
|
vfs::FileSystem *VFS,
|
|
|
|
StringRef FilePath) {
|
|
|
|
const auto &PreprocessorOpts = Invocation.getPreprocessorOpts();
|
2011-10-28 03:44:25 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
// Try to determine if the main file has been remapped, either from the
|
|
|
|
// command line (to another file) or directly through the compiler
|
|
|
|
// invocation (to a memory buffer).
|
|
|
|
llvm::MemoryBuffer *Buffer = nullptr;
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> BufferOwner;
|
|
|
|
auto FileStatus = VFS->status(FilePath);
|
|
|
|
if (FileStatus) {
|
|
|
|
llvm::sys::fs::UniqueID MainFileID = FileStatus->getUniqueID();
|
2011-10-28 01:55:18 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
// Check whether there is a file-file remapping of the main file
|
|
|
|
for (const auto &RF : PreprocessorOpts.RemappedFiles) {
|
|
|
|
std::string MPath(RF.first);
|
|
|
|
auto MPathStatus = VFS->status(MPath);
|
|
|
|
if (MPathStatus) {
|
|
|
|
llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
|
|
|
|
if (MainFileID == MID) {
|
|
|
|
// We found a remapping. Try to load the resulting, remapped source.
|
|
|
|
BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second));
|
|
|
|
if (!BufferOwner)
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-10-28 01:55:18 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
// Check whether there is a file-buffer remapping. It supercedes the
|
|
|
|
// file-file remapping.
|
|
|
|
for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
|
|
|
|
std::string MPath(RB.first);
|
|
|
|
auto MPathStatus = VFS->status(MPath);
|
|
|
|
if (MPathStatus) {
|
|
|
|
llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID();
|
|
|
|
if (MainFileID == MID) {
|
|
|
|
// We found a remapping.
|
|
|
|
BufferOwner.reset();
|
|
|
|
Buffer = const_cast<llvm::MemoryBuffer *>(RB.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-10-28 01:55:18 +08:00
|
|
|
}
|
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
// If the main source file was not remapped, load it now.
|
|
|
|
if (!Buffer && !BufferOwner) {
|
|
|
|
BufferOwner = valueOrNull(VFS->getBufferForFile(FilePath));
|
|
|
|
if (!BufferOwner)
|
|
|
|
return nullptr;
|
2011-10-28 01:55:18 +08:00
|
|
|
}
|
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
if (BufferOwner)
|
|
|
|
return BufferOwner;
|
|
|
|
if (!Buffer)
|
|
|
|
return nullptr;
|
|
|
|
return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath);
|
2011-10-28 01:55:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
struct ASTUnit::ASTWriterData {
|
|
|
|
SmallString<128> Buffer;
|
|
|
|
llvm::BitstreamWriter Stream;
|
|
|
|
ASTWriter Writer;
|
|
|
|
|
Reapply "Modules: Cache PCMs in memory and avoid a use-after-free"
This reverts commit r298185, effectively reapplying r298165, after fixing the
new unit tests (PR32338). The memory buffer generator doesn't null-terminate
the MemoryBuffer it creates; this version of the commit informs getMemBuffer
about that to avoid the assert.
Original commit message follows:
----
Clang's internal build system for implicit modules uses lock files to
ensure that after a process writes a PCM it will read the same one back
in (without contention from other -cc1 commands). Since PCMs are read
from disk repeatedly while invalidating, building, and importing, the
lock is not released quickly. Furthermore, the LockFileManager is not
robust in every environment. Other -cc1 commands can stall until
timeout (after about eight minutes).
This commit changes the lock file from being necessary for correctness
to a (possibly dubious) performance hack. The remaining benefit is to
reduce duplicate work in competing -cc1 commands which depend on the
same module. Follow-up commits will change the internal build system to
continue after a timeout, and reduce the timeout. Perhaps we should
reconsider blocking at all.
This also fixes a use-after-free, when one part of a compilation
validates a PCM and starts using it, and another tries to swap out the
PCM for something new.
The PCMCache is a new type called MemoryBufferCache, which saves memory
buffers based on their filename. Its ownership is shared by the
CompilerInstance and ModuleManager.
- The ModuleManager stores PCMs there that it loads from disk, never
touching the disk if the cache is hot.
- When modules fail to validate, they're removed from the cache.
- When a CompilerInstance is spawned to build a new module, each
already-loaded PCM is assumed to be valid, and is frozen to avoid
the use-after-free.
- Any newly-built module is written directly to the cache to avoid the
round-trip to the filesystem, making lock files unnecessary for
correctness.
Original patch by Manman Ren; most testcases by Adrian Prantl!
llvm-svn: 298278
2017-03-21 01:58:26 +08:00
|
|
|
ASTWriterData(MemoryBufferCache &PCMCache)
|
|
|
|
: Stream(Buffer), Writer(Stream, Buffer, PCMCache, {}) {}
|
2012-10-12 00:05:00 +08:00
|
|
|
};
|
|
|
|
|
2011-10-31 15:19:59 +08:00
|
|
|
void ASTUnit::clearFileLevelDecls() {
|
2014-02-20 07:44:52 +08:00
|
|
|
llvm::DeleteContainerSeconds(FileDecls);
|
2011-10-31 15:19:59 +08:00
|
|
|
}
|
|
|
|
|
2010-08-04 13:53:38 +08:00
|
|
|
/// \brief After failing to build a precompiled preamble (due to
|
|
|
|
/// errors in the source that occurs in the preamble), the number of
|
|
|
|
/// reparses during which we'll skip even trying to precompile the
|
|
|
|
/// preamble.
|
|
|
|
const unsigned DefaultPreambleRebuildInterval = 5;
|
|
|
|
|
2010-11-17 08:13:31 +08:00
|
|
|
/// \brief Tracks the number of ASTUnit objects that are currently active.
|
|
|
|
///
|
|
|
|
/// Used for debugging purposes only.
|
2014-03-03 01:08:31 +08:00
|
|
|
static std::atomic<unsigned> ActiveASTUnitObjects;
|
2010-11-17 08:13:31 +08:00
|
|
|
|
2010-04-06 05:10:19 +08:00
|
|
|
ASTUnit::ASTUnit(bool _MainFileIsAST)
|
2014-05-22 12:46:25 +08:00
|
|
|
: Reader(nullptr), HadModuleLoaderFatalFailure(false),
|
2013-05-24 13:44:08 +08:00
|
|
|
OnlyLocalDecls(false), CaptureDiagnostics(false),
|
2018-02-26 23:16:42 +08:00
|
|
|
MainFileIsAST(_MainFileIsAST),
|
2011-08-26 06:30:56 +08:00
|
|
|
TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
|
2011-03-05 09:03:48 +08:00
|
|
|
OwnsRemappedFileBuffers(true),
|
2010-10-28 23:44:59 +08:00
|
|
|
NumStoredDiagnosticsFromDriver(0),
|
2014-08-14 01:08:22 +08:00
|
|
|
PreambleRebuildCounter(0),
|
2014-08-14 00:47:00 +08:00
|
|
|
NumWarningsInPreamble(0),
|
2010-08-17 08:40:40 +08:00
|
|
|
ShouldCacheCodeCompletionResults(false),
|
2012-07-12 04:59:04 +08:00
|
|
|
IncludeBriefCommentsInCodeCompletion(false), UserFilesAreVolatile(false),
|
2011-02-17 02:16:54 +08:00
|
|
|
CompletionCacheTopLevelHashValue(0),
|
|
|
|
PreambleTopLevelHashValue(0),
|
|
|
|
CurrentTopLevelHashValue(0),
|
2018-02-26 23:16:42 +08:00
|
|
|
UnsafeToFree(false) {
|
2014-03-03 01:08:31 +08:00
|
|
|
if (getenv("LIBCLANG_OBJTRACKING"))
|
|
|
|
fprintf(stderr, "+++ %u translation units\n", ++ActiveASTUnitObjects);
|
2010-07-31 04:58:08 +08:00
|
|
|
}
|
2010-04-06 05:10:19 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
ASTUnit::~ASTUnit() {
|
2013-05-04 06:58:43 +08:00
|
|
|
// If we loaded from an AST file, balance out the BeginSourceFile call.
|
|
|
|
if (MainFileIsAST && getDiagnostics().getClient()) {
|
|
|
|
getDiagnostics().getClient()->EndSourceFile();
|
|
|
|
}
|
|
|
|
|
2011-10-31 15:19:59 +08:00
|
|
|
clearFileLevelDecls();
|
|
|
|
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-27 05:36:20 +08:00
|
|
|
// Free the buffers associated with remapped files. We are required to
|
|
|
|
// perform this operation here because we explicitly request that the
|
|
|
|
// compiler instance *not* free these buffers for each invocation of the
|
|
|
|
// parser.
|
2017-01-07 03:49:01 +08:00
|
|
|
if (Invocation && OwnsRemappedFileBuffers) {
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-27 05:36:20 +08:00
|
|
|
PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
|
2014-07-07 15:47:20 +08:00
|
|
|
for (const auto &RB : PPOpts.RemappedFileBuffers)
|
|
|
|
delete RB.second;
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-27 05:36:20 +08:00
|
|
|
}
|
2010-08-19 09:33:06 +08:00
|
|
|
|
2018-02-26 23:16:42 +08:00
|
|
|
ClearCachedCompletionResults();
|
|
|
|
|
2014-03-03 01:08:31 +08:00
|
|
|
if (getenv("LIBCLANG_OBJTRACKING"))
|
|
|
|
fprintf(stderr, "--- %u translation units\n", --ActiveASTUnitObjects);
|
2010-07-20 05:46:24 +08:00
|
|
|
}
|
|
|
|
|
2017-01-06 03:48:07 +08:00
|
|
|
void ASTUnit::setPreprocessor(std::shared_ptr<Preprocessor> PP) {
|
|
|
|
this->PP = std::move(PP);
|
|
|
|
}
|
2012-01-18 02:48:07 +08:00
|
|
|
|
2018-02-26 23:16:42 +08:00
|
|
|
/// \brief Determine the set of code-completion contexts in which this
|
2010-08-15 14:18:01 +08:00
|
|
|
/// declaration should be shown.
|
2013-01-24 01:21:11 +08:00
|
|
|
static unsigned getDeclShowContexts(const NamedDecl *ND,
|
2010-08-17 07:05:20 +08:00
|
|
|
const LangOptions &LangOpts,
|
|
|
|
bool &IsNestedNameSpecifier) {
|
|
|
|
IsNestedNameSpecifier = false;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
if (isa<UsingShadowDecl>(ND))
|
|
|
|
ND = dyn_cast<NamedDecl>(ND->getUnderlyingDecl());
|
|
|
|
if (!ND)
|
|
|
|
return 0;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2012-08-14 11:13:00 +08:00
|
|
|
uint64_t Contexts = 0;
|
2018-02-26 23:16:42 +08:00
|
|
|
if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) ||
|
2017-09-08 17:31:13 +08:00
|
|
|
isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND) ||
|
|
|
|
isa<TypeAliasTemplateDecl>(ND)) {
|
2010-08-15 14:18:01 +08:00
|
|
|
// Types can appear in these contexts.
|
|
|
|
if (LangOpts.CPlusPlus || !isa<TagDecl>(ND))
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_TopLevel)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCIvarList)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ClassStructUnion)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Statement)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Type)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ParenthesizedExpression);
|
2010-08-15 14:18:01 +08:00
|
|
|
|
|
|
|
// In C++, types can appear in expressions contexts (for functional casts).
|
|
|
|
if (LangOpts.CPlusPlus)
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_Expression);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
// In Objective-C, message sends can send interfaces. In Objective-C++,
|
|
|
|
// all types are available due to functional casts.
|
|
|
|
if (LangOpts.CPlusPlus || isa<ObjCInterfaceDecl>(ND))
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-07-08 00:03:39 +08:00
|
|
|
// In Objective-C, you can only be a subclass of another Objective-C class
|
2017-11-14 09:46:24 +08:00
|
|
|
if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
|
|
|
|
// Objective-C interfaces can be used in a class property expression.
|
|
|
|
if (ID->getDefinition())
|
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_Expression);
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName);
|
2017-11-14 09:46:24 +08:00
|
|
|
}
|
2010-08-15 14:18:01 +08:00
|
|
|
|
|
|
|
// Deal with tag names.
|
|
|
|
if (isa<EnumDecl>(ND)) {
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_EnumTag);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 07:05:20 +08:00
|
|
|
// Part of the nested-name-specifier in C++0x.
|
2013-01-02 19:42:31 +08:00
|
|
|
if (LangOpts.CPlusPlus11)
|
2010-08-17 07:05:20 +08:00
|
|
|
IsNestedNameSpecifier = true;
|
2013-01-24 01:21:11 +08:00
|
|
|
} else if (const RecordDecl *Record = dyn_cast<RecordDecl>(ND)) {
|
2010-08-15 14:18:01 +08:00
|
|
|
if (Record->isUnion())
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_UnionTag);
|
2010-08-15 14:18:01 +08:00
|
|
|
else
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_ClassOrStructTag);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
if (LangOpts.CPlusPlus)
|
2010-08-17 07:05:20 +08:00
|
|
|
IsNestedNameSpecifier = true;
|
2010-09-24 07:01:17 +08:00
|
|
|
} else if (isa<ClassTemplateDecl>(ND))
|
2010-08-17 07:05:20 +08:00
|
|
|
IsNestedNameSpecifier = true;
|
2010-08-15 14:18:01 +08:00
|
|
|
} else if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
|
|
|
|
// Values can appear in these contexts.
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts = (1LL << CodeCompletionContext::CCC_Statement)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Expression)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ParenthesizedExpression)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver);
|
2010-08-15 14:18:01 +08:00
|
|
|
} else if (isa<ObjCProtocolDecl>(ND)) {
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts = (1LL << CodeCompletionContext::CCC_ObjCProtocolName);
|
2011-07-08 00:03:39 +08:00
|
|
|
} else if (isa<ObjCCategoryDecl>(ND)) {
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts = (1LL << CodeCompletionContext::CCC_ObjCCategoryName);
|
2010-08-15 14:18:01 +08:00
|
|
|
} else if (isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) {
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts = (1LL << CodeCompletionContext::CCC_Namespace);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
// Part of the nested-name-specifier.
|
2010-08-17 07:05:20 +08:00
|
|
|
IsNestedNameSpecifier = true;
|
2010-08-15 14:18:01 +08:00
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
return Contexts;
|
|
|
|
}
|
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
void ASTUnit::CacheCodeCompletionResults() {
|
|
|
|
if (!TheSema)
|
|
|
|
return;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
SimpleTimer Timer(WantTiming);
|
2010-11-10 04:00:56 +08:00
|
|
|
Timer.setOutput("Cache global code completions for " + getMainFileName());
|
2010-08-14 06:48:40 +08:00
|
|
|
|
|
|
|
// Clear out the previous results.
|
|
|
|
ClearCachedCompletionResults();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
// Gather the set of global code completions.
|
2010-08-25 14:19:51 +08:00
|
|
|
typedef CodeCompletionResult Result;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Result, 8> Results;
|
2017-01-07 03:49:01 +08:00
|
|
|
CachedCompletionAllocator = std::make_shared<GlobalCodeCompletionAllocator>();
|
2012-11-16 11:34:57 +08:00
|
|
|
CodeCompletionTUInfo CCTUInfo(CachedCompletionAllocator);
|
2012-04-11 01:23:48 +08:00
|
|
|
TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator,
|
2012-11-16 11:34:57 +08:00
|
|
|
CCTUInfo, Results);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
// Translate global code completions into cached completions.
|
2010-08-17 02:08:11 +08:00
|
|
|
llvm::DenseMap<CanQualType, unsigned> CompletionTypes;
|
2015-07-07 14:20:19 +08:00
|
|
|
CodeCompletionContext CCContext(CodeCompletionContext::CCC_TopLevel);
|
2015-02-07 02:36:04 +08:00
|
|
|
|
|
|
|
for (Result &R : Results) {
|
|
|
|
switch (R.Kind) {
|
2010-08-15 14:18:01 +08:00
|
|
|
case Result::RK_Declaration: {
|
2010-08-17 07:05:20 +08:00
|
|
|
bool IsNestedNameSpecifier = false;
|
2010-08-15 14:18:01 +08:00
|
|
|
CachedCodeCompletionResult CachedResult;
|
2015-02-07 02:36:04 +08:00
|
|
|
CachedResult.Completion = R.CreateCodeCompletionString(
|
2015-07-07 14:20:19 +08:00
|
|
|
*TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo,
|
2015-02-07 02:36:04 +08:00
|
|
|
IncludeBriefCommentsInCodeCompletion);
|
|
|
|
CachedResult.ShowInContexts = getDeclShowContexts(
|
|
|
|
R.Declaration, Ctx->getLangOpts(), IsNestedNameSpecifier);
|
|
|
|
CachedResult.Priority = R.Priority;
|
|
|
|
CachedResult.Kind = R.CursorKind;
|
|
|
|
CachedResult.Availability = R.Availability;
|
2010-08-17 00:46:30 +08:00
|
|
|
|
2018-02-26 23:16:42 +08:00
|
|
|
// Keep track of the type of this completion in an ASTContext-agnostic
|
2010-08-17 02:08:11 +08:00
|
|
|
// way.
|
2015-02-07 02:36:04 +08:00
|
|
|
QualType UsageType = getDeclUsageType(*Ctx, R.Declaration);
|
2010-08-17 02:08:11 +08:00
|
|
|
if (UsageType.isNull()) {
|
2010-08-17 00:46:30 +08:00
|
|
|
CachedResult.TypeClass = STC_Void;
|
2010-08-17 02:08:11 +08:00
|
|
|
CachedResult.Type = 0;
|
|
|
|
} else {
|
|
|
|
CanQualType CanUsageType
|
|
|
|
= Ctx->getCanonicalType(UsageType.getUnqualifiedType());
|
|
|
|
CachedResult.TypeClass = getSimplifiedTypeClass(CanUsageType);
|
|
|
|
|
|
|
|
// Determine whether we have already seen this type. If so, we save
|
2018-02-26 23:16:42 +08:00
|
|
|
// ourselves the work of formatting the type string by using the
|
2010-08-17 02:08:11 +08:00
|
|
|
// temporary, CanQualType-based hash table to find the associated value.
|
|
|
|
unsigned &TypeValue = CompletionTypes[CanUsageType];
|
|
|
|
if (TypeValue == 0) {
|
|
|
|
TypeValue = CompletionTypes.size();
|
|
|
|
CachedCompletionTypes[QualType(CanUsageType).getAsString()]
|
|
|
|
= TypeValue;
|
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 02:08:11 +08:00
|
|
|
CachedResult.Type = TypeValue;
|
2010-08-17 00:46:30 +08:00
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
CachedCompletionResults.push_back(CachedResult);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 07:05:20 +08:00
|
|
|
/// Handle nested-name-specifiers in C++.
|
2015-02-07 02:36:04 +08:00
|
|
|
if (TheSema->Context.getLangOpts().CPlusPlus && IsNestedNameSpecifier &&
|
|
|
|
!R.StartsNestedNameSpecifier) {
|
2010-08-17 07:05:20 +08:00
|
|
|
// The contexts in which a nested-name-specifier can appear in C++.
|
2012-08-14 11:13:00 +08:00
|
|
|
uint64_t NNSContexts
|
|
|
|
= (1LL << CodeCompletionContext::CCC_TopLevel)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCIvarList)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ClassStructUnion)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Statement)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Expression)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_EnumTag)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_UnionTag)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ClassOrStructTag)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Type)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_PotentiallyQualifiedName)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ParenthesizedExpression);
|
2010-08-17 07:05:20 +08:00
|
|
|
|
2015-02-07 02:36:04 +08:00
|
|
|
if (isa<NamespaceDecl>(R.Declaration) ||
|
|
|
|
isa<NamespaceAliasDecl>(R.Declaration))
|
2012-08-14 11:13:00 +08:00
|
|
|
NNSContexts |= (1LL << CodeCompletionContext::CCC_Namespace);
|
2010-08-17 07:05:20 +08:00
|
|
|
|
2018-02-26 23:16:42 +08:00
|
|
|
if (unsigned RemainingContexts
|
2010-08-17 07:05:20 +08:00
|
|
|
= NNSContexts & ~CachedResult.ShowInContexts) {
|
2018-02-26 23:16:42 +08:00
|
|
|
// If there any contexts where this completion can be a
|
|
|
|
// nested-name-specifier but isn't already an option, create a
|
2010-08-17 07:05:20 +08:00
|
|
|
// nested-name-specifier completion.
|
2015-02-07 02:36:04 +08:00
|
|
|
R.StartsNestedNameSpecifier = true;
|
|
|
|
CachedResult.Completion = R.CreateCodeCompletionString(
|
2015-07-07 14:20:19 +08:00
|
|
|
*TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo,
|
2015-02-07 02:36:04 +08:00
|
|
|
IncludeBriefCommentsInCodeCompletion);
|
2010-08-17 07:05:20 +08:00
|
|
|
CachedResult.ShowInContexts = RemainingContexts;
|
|
|
|
CachedResult.Priority = CCP_NestedNameSpecifier;
|
|
|
|
CachedResult.TypeClass = STC_Void;
|
|
|
|
CachedResult.Type = 0;
|
|
|
|
CachedCompletionResults.push_back(CachedResult);
|
|
|
|
}
|
|
|
|
}
|
2010-08-14 06:48:40 +08:00
|
|
|
break;
|
2010-08-15 14:18:01 +08:00
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
case Result::RK_Keyword:
|
|
|
|
case Result::RK_Pattern:
|
|
|
|
// Ignore keywords and patterns; we don't care, since they are so
|
|
|
|
// easily regenerated.
|
|
|
|
break;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
case Result::RK_Macro: {
|
|
|
|
CachedCodeCompletionResult CachedResult;
|
2015-02-07 02:36:04 +08:00
|
|
|
CachedResult.Completion = R.CreateCodeCompletionString(
|
2015-07-07 14:20:19 +08:00
|
|
|
*TheSema, CCContext, *CachedCompletionAllocator, CCTUInfo,
|
2015-02-07 02:36:04 +08:00
|
|
|
IncludeBriefCommentsInCodeCompletion);
|
2010-08-14 06:48:40 +08:00
|
|
|
CachedResult.ShowInContexts
|
2012-08-14 11:13:00 +08:00
|
|
|
= (1LL << CodeCompletionContext::CCC_TopLevel)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCInterface)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCImplementation)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCIvarList)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ClassStructUnion)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Statement)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Expression)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_MacroNameUse)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_PreprocessorExpression)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ParenthesizedExpression)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_OtherWithMacros);
|
2015-02-07 02:36:04 +08:00
|
|
|
|
|
|
|
CachedResult.Priority = R.Priority;
|
|
|
|
CachedResult.Kind = R.CursorKind;
|
|
|
|
CachedResult.Availability = R.Availability;
|
2010-08-17 00:18:59 +08:00
|
|
|
CachedResult.TypeClass = STC_Void;
|
2010-08-17 02:08:11 +08:00
|
|
|
CachedResult.Type = 0;
|
2010-08-14 06:48:40 +08:00
|
|
|
CachedCompletionResults.push_back(CachedResult);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-02-17 02:16:54 +08:00
|
|
|
// Save the current top-level hash value.
|
|
|
|
CompletionCacheTopLevelHashValue = CurrentTopLevelHashValue;
|
2010-08-14 06:48:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::ClearCachedCompletionResults() {
|
|
|
|
CachedCompletionResults.clear();
|
2010-08-17 02:08:11 +08:00
|
|
|
CachedCompletionTypes.clear();
|
2014-05-22 12:46:25 +08:00
|
|
|
CachedCompletionAllocator = nullptr;
|
2010-08-14 06:48:40 +08:00
|
|
|
}
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
namespace {
|
|
|
|
|
2010-08-19 07:56:43 +08:00
|
|
|
/// \brief Gathers information from ASTReader that will be used to initialize
|
2009-06-20 16:08:23 +08:00
|
|
|
/// a Preprocessor.
|
2010-08-19 07:57:06 +08:00
|
|
|
class ASTInfoCollector : public ASTReaderListener {
|
2011-09-02 07:39:15 +08:00
|
|
|
Preprocessor &PP;
|
2017-06-30 07:23:46 +08:00
|
|
|
ASTContext *Context;
|
2017-06-06 08:32:01 +08:00
|
|
|
HeaderSearchOptions &HSOpts;
|
|
|
|
PreprocessorOptions &PPOpts;
|
2009-06-20 16:08:23 +08:00
|
|
|
LangOptions &LangOpt;
|
2014-07-06 13:26:44 +08:00
|
|
|
std::shared_ptr<TargetOptions> &TargetOpts;
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<TargetInfo> &Target;
|
2009-06-20 16:08:23 +08:00
|
|
|
unsigned &Counter;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-09-02 08:18:52 +08:00
|
|
|
bool InitializedLanguage;
|
2009-06-20 16:08:23 +08:00
|
|
|
public:
|
2017-06-30 07:23:46 +08:00
|
|
|
ASTInfoCollector(Preprocessor &PP, ASTContext *Context,
|
2017-06-06 08:32:01 +08:00
|
|
|
HeaderSearchOptions &HSOpts, PreprocessorOptions &PPOpts,
|
|
|
|
LangOptions &LangOpt,
|
2014-07-06 13:26:44 +08:00
|
|
|
std::shared_ptr<TargetOptions> &TargetOpts,
|
|
|
|
IntrusiveRefCntPtr<TargetInfo> &Target, unsigned &Counter)
|
2017-06-06 08:32:01 +08:00
|
|
|
: PP(PP), Context(Context), HSOpts(HSOpts), PPOpts(PPOpts),
|
|
|
|
LangOpt(LangOpt), TargetOpts(TargetOpts), Target(Target),
|
|
|
|
Counter(Counter), InitializedLanguage(false) {}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-10-31 10:28:58 +08:00
|
|
|
bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
|
|
|
|
bool AllowCompatibleDifferences) override {
|
2012-10-12 00:05:00 +08:00
|
|
|
if (InitializedLanguage)
|
2011-09-02 07:39:15 +08:00
|
|
|
return false;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
LangOpt = LangOpts;
|
2011-09-02 08:18:52 +08:00
|
|
|
InitializedLanguage = true;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
updated();
|
2009-06-20 16:08:23 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2017-06-06 08:32:01 +08:00
|
|
|
virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
|
|
|
|
StringRef SpecificModuleCachePath,
|
|
|
|
bool Complain) override {
|
|
|
|
this->HSOpts = HSOpts;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool
|
|
|
|
ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, bool Complain,
|
|
|
|
std::string &SuggestedPredefines) override {
|
|
|
|
this->PPOpts = PPOpts;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-03-14 12:47:43 +08:00
|
|
|
bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain,
|
|
|
|
bool AllowCompatibleDifferences) override {
|
2011-09-02 07:39:15 +08:00
|
|
|
// If we've already initialized the target, don't do it again.
|
2012-10-12 00:05:00 +08:00
|
|
|
if (Target)
|
2011-09-02 07:39:15 +08:00
|
|
|
return false;
|
2014-07-06 13:26:44 +08:00
|
|
|
|
|
|
|
this->TargetOpts = std::make_shared<TargetOptions>(TargetOpts);
|
|
|
|
Target =
|
|
|
|
TargetInfo::CreateTargetInfo(PP.getDiagnostics(), this->TargetOpts);
|
2012-09-15 04:24:53 +08:00
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
updated();
|
2009-06-20 16:08:23 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
void ReadCounter(const serialization::ModuleFile &M,
|
|
|
|
unsigned Value) override {
|
2009-06-20 16:08:23 +08:00
|
|
|
Counter = Value;
|
|
|
|
}
|
2012-09-15 04:24:53 +08:00
|
|
|
|
|
|
|
private:
|
2012-10-12 00:05:00 +08:00
|
|
|
void updated() {
|
|
|
|
if (!Target || !InitializedLanguage)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Inform the target of the language options.
|
|
|
|
//
|
|
|
|
// FIXME: We shouldn't need to do this, the target should be immutable once
|
|
|
|
// created. This complexity should be lifted elsewhere.
|
2014-07-06 13:14:24 +08:00
|
|
|
Target->adjust(LangOpt);
|
2012-10-12 00:05:00 +08:00
|
|
|
|
|
|
|
// Initialize the preprocessor.
|
|
|
|
PP.Initialize(*Target);
|
|
|
|
|
2017-06-30 07:23:46 +08:00
|
|
|
if (!Context)
|
|
|
|
return;
|
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
// Initialize the ASTContext
|
2017-06-30 07:23:46 +08:00
|
|
|
Context->InitBuiltinTypes(*Target);
|
2013-02-22 22:21:27 +08:00
|
|
|
|
2017-08-26 02:07:03 +08:00
|
|
|
// Adjust printing policy based on language options.
|
|
|
|
Context->setPrintingPolicy(PrintingPolicy(LangOpt));
|
|
|
|
|
2013-02-22 22:21:27 +08:00
|
|
|
// We didn't have access to the comment options when the ASTContext was
|
|
|
|
// constructed, so register them now.
|
2017-06-30 07:23:46 +08:00
|
|
|
Context->getCommentCommandTraits().registerCommentOptions(
|
2013-02-22 22:21:27 +08:00
|
|
|
LangOpt.CommentOpts);
|
2012-09-15 04:24:53 +08:00
|
|
|
}
|
2009-06-20 16:08:23 +08:00
|
|
|
};
|
|
|
|
|
2013-05-04 06:58:43 +08:00
|
|
|
/// \brief Diagnostic consumer that saves each diagnostic it is given.
|
2011-09-26 08:01:39 +08:00
|
|
|
class StoredDiagnosticConsumer : public DiagnosticConsumer {
|
2017-06-21 18:24:58 +08:00
|
|
|
SmallVectorImpl<StoredDiagnostic> *StoredDiags;
|
|
|
|
SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags;
|
|
|
|
const LangOptions *LangOpts;
|
2013-05-04 06:58:43 +08:00
|
|
|
SourceManager *SourceMgr;
|
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
public:
|
2017-06-21 18:24:58 +08:00
|
|
|
StoredDiagnosticConsumer(
|
|
|
|
SmallVectorImpl<StoredDiagnostic> *StoredDiags,
|
|
|
|
SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
|
|
|
|
: StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags),
|
|
|
|
LangOpts(nullptr), SourceMgr(nullptr) {
|
|
|
|
assert((StoredDiags || StandaloneDiags) &&
|
|
|
|
"No output collections were passed to StoredDiagnosticConsumer.");
|
|
|
|
}
|
2013-05-04 06:58:43 +08:00
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
void BeginSourceFile(const LangOptions &LangOpts,
|
2014-05-22 12:46:25 +08:00
|
|
|
const Preprocessor *PP = nullptr) override {
|
2017-06-21 18:24:58 +08:00
|
|
|
this->LangOpts = &LangOpts;
|
2013-05-04 06:58:43 +08:00
|
|
|
if (PP)
|
|
|
|
SourceMgr = &PP->getSourceManager();
|
|
|
|
}
|
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
void HandleDiagnostic(DiagnosticsEngine::Level Level,
|
|
|
|
const Diagnostic &Info) override;
|
2010-02-19 02:08:43 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/// \brief RAII object that optionally captures diagnostics, if
|
|
|
|
/// there is no diagnostic client to capture them already.
|
|
|
|
class CaptureDroppedDiagnostics {
|
2011-09-26 07:23:43 +08:00
|
|
|
DiagnosticsEngine &Diags;
|
2011-09-26 08:01:39 +08:00
|
|
|
StoredDiagnosticConsumer Client;
|
2011-09-26 07:39:51 +08:00
|
|
|
DiagnosticConsumer *PreviousClient;
|
2014-11-18 07:46:02 +08:00
|
|
|
std::unique_ptr<DiagnosticConsumer> OwningPreviousClient;
|
2010-02-19 02:08:43 +08:00
|
|
|
|
|
|
|
public:
|
2011-09-26 07:23:43 +08:00
|
|
|
CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
|
2017-06-21 18:24:58 +08:00
|
|
|
SmallVectorImpl<StoredDiagnostic> *StoredDiags,
|
|
|
|
SmallVectorImpl<ASTUnit::StandaloneDiagnostic> *StandaloneDiags)
|
|
|
|
: Diags(Diags), Client(StoredDiags, StandaloneDiags), PreviousClient(nullptr)
|
2010-02-19 02:08:43 +08:00
|
|
|
{
|
2014-05-22 12:46:25 +08:00
|
|
|
if (RequestCapture || Diags.getClient() == nullptr) {
|
2014-11-18 07:46:02 +08:00
|
|
|
OwningPreviousClient = Diags.takeClient();
|
|
|
|
PreviousClient = Diags.getClient();
|
|
|
|
Diags.setClient(&Client, false);
|
2010-08-19 06:29:43 +08:00
|
|
|
}
|
2010-02-19 02:08:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
~CaptureDroppedDiagnostics() {
|
2014-11-18 07:46:02 +08:00
|
|
|
if (Diags.getClient() == &Client)
|
|
|
|
Diags.setClient(PreviousClient, !!OwningPreviousClient.release());
|
2010-02-19 02:08:43 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
static ASTUnit::StandaloneDiagnostic
|
|
|
|
makeStandaloneDiagnostic(const LangOptions &LangOpts,
|
|
|
|
const StoredDiagnostic &InDiag);
|
|
|
|
|
2011-09-26 08:01:39 +08:00
|
|
|
void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
|
2017-06-21 18:24:58 +08:00
|
|
|
const Diagnostic &Info) {
|
2010-11-19 04:06:46 +08:00
|
|
|
// Default implementation (Warnings/errors count).
|
2011-09-26 07:39:51 +08:00
|
|
|
DiagnosticConsumer::HandleDiagnostic(Level, Info);
|
2010-11-19 04:06:46 +08:00
|
|
|
|
2013-05-04 06:58:43 +08:00
|
|
|
// Only record the diagnostic if it's part of the source manager we know
|
|
|
|
// about. This effectively drops diagnostics from modules we're building.
|
|
|
|
// FIXME: In the long run, ee don't want to drop source managers from modules.
|
2017-06-21 18:24:58 +08:00
|
|
|
if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) {
|
|
|
|
StoredDiagnostic *ResultDiag = nullptr;
|
|
|
|
if (StoredDiags) {
|
|
|
|
StoredDiags->emplace_back(Level, Info);
|
|
|
|
ResultDiag = &StoredDiags->back();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (StandaloneDiags) {
|
|
|
|
llvm::Optional<StoredDiagnostic> StoredDiag = llvm::None;
|
|
|
|
if (!ResultDiag) {
|
|
|
|
StoredDiag.emplace(Level, Info);
|
|
|
|
ResultDiag = StoredDiag.getPointer();
|
|
|
|
}
|
|
|
|
StandaloneDiags->push_back(
|
|
|
|
makeStandaloneDiagnostic(*LangOpts, *ResultDiag));
|
|
|
|
}
|
|
|
|
}
|
2010-02-19 02:08:43 +08:00
|
|
|
}
|
|
|
|
|
2017-01-30 14:05:58 +08:00
|
|
|
IntrusiveRefCntPtr<ASTReader> ASTUnit::getASTReader() const {
|
|
|
|
return Reader;
|
|
|
|
}
|
|
|
|
|
2013-05-10 09:28:51 +08:00
|
|
|
ASTMutationListener *ASTUnit::getASTMutationListener() {
|
|
|
|
if (WriterData)
|
|
|
|
return &WriterData->Writer;
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2013-05-10 09:28:51 +08:00
|
|
|
}
|
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
ASTDeserializationListener *ASTUnit::getDeserializationListener() {
|
|
|
|
if (WriterData)
|
|
|
|
return &WriterData->Writer;
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2012-10-12 00:05:00 +08:00
|
|
|
}
|
|
|
|
|
2014-08-27 04:17:44 +08:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer>
|
|
|
|
ASTUnit::getBufferForFile(StringRef Filename, std::string *ErrorStr) {
|
2010-11-23 16:35:12 +08:00
|
|
|
assert(FileMgr);
|
2014-10-27 06:44:13 +08:00
|
|
|
auto Buffer = FileMgr->getBufferForFile(Filename);
|
|
|
|
if (Buffer)
|
|
|
|
return std::move(*Buffer);
|
|
|
|
if (ErrorStr)
|
|
|
|
*ErrorStr = Buffer.getError().message();
|
|
|
|
return nullptr;
|
2010-11-04 06:45:23 +08:00
|
|
|
}
|
|
|
|
|
2010-11-11 08:39:14 +08:00
|
|
|
/// \brief Configure the diagnostics object for use with ASTUnit.
|
2014-10-15 08:33:06 +08:00
|
|
|
void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
2010-11-11 08:39:14 +08:00
|
|
|
ASTUnit &AST, bool CaptureDiagnostics) {
|
2014-10-15 08:33:06 +08:00
|
|
|
assert(Diags.get() && "no DiagnosticsEngine was provided");
|
|
|
|
if (CaptureDiagnostics)
|
2017-06-21 18:24:58 +08:00
|
|
|
Diags->setClient(new StoredDiagnosticConsumer(&AST.StoredDiagnostics, nullptr));
|
2010-11-11 08:39:14 +08:00
|
|
|
}
|
|
|
|
|
2014-08-11 03:08:04 +08:00
|
|
|
std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
|
2015-08-28 03:46:20 +08:00
|
|
|
const std::string &Filename, const PCHContainerReader &PCHContainerRdr,
|
2017-06-30 07:23:46 +08:00
|
|
|
WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
2015-08-28 03:46:20 +08:00
|
|
|
const FileSystemOptions &FileSystemOpts, bool UseDebugInfo,
|
|
|
|
bool OnlyLocalDecls, ArrayRef<RemappedFile> RemappedFiles,
|
|
|
|
bool CaptureDiagnostics, bool AllowPCHWithCompilerErrors,
|
|
|
|
bool UserFilesAreVolatile) {
|
2014-03-08 04:03:18 +08:00
|
|
|
std::unique_ptr<ASTUnit> AST(new ASTUnit(true));
|
2011-03-18 10:06:56 +08:00
|
|
|
|
|
|
|
// Recover resources if we crash before exiting this method.
|
2011-03-22 09:15:24 +08:00
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
|
|
|
|
ASTUnitCleanup(AST.get());
|
2011-09-26 07:23:43 +08:00
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
|
|
|
|
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
|
2014-07-05 11:08:06 +08:00
|
|
|
DiagCleanup(Diags.get());
|
2011-03-18 10:06:56 +08:00
|
|
|
|
2014-10-15 07:36:06 +08:00
|
|
|
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2017-06-06 02:10:11 +08:00
|
|
|
AST->LangOpts = std::make_shared<LangOptions>();
|
2009-10-17 04:01:17 +08:00
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
2010-11-11 08:39:14 +08:00
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
2010-04-06 07:52:57 +08:00
|
|
|
AST->Diagnostics = Diags;
|
2014-04-16 02:16:25 +08:00
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();
|
|
|
|
AST->FileMgr = new FileManager(FileSystemOpts, VFS);
|
2012-07-12 04:59:04 +08:00
|
|
|
AST->UserFilesAreVolatile = UserFilesAreVolatile;
|
2011-03-22 02:40:17 +08:00
|
|
|
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
|
2012-07-12 04:59:04 +08:00
|
|
|
AST->getFileManager(),
|
|
|
|
UserFilesAreVolatile);
|
Reapply "Modules: Cache PCMs in memory and avoid a use-after-free"
This reverts commit r298185, effectively reapplying r298165, after fixing the
new unit tests (PR32338). The memory buffer generator doesn't null-terminate
the MemoryBuffer it creates; this version of the commit informs getMemBuffer
about that to avoid the assert.
Original commit message follows:
----
Clang's internal build system for implicit modules uses lock files to
ensure that after a process writes a PCM it will read the same one back
in (without contention from other -cc1 commands). Since PCMs are read
from disk repeatedly while invalidating, building, and importing, the
lock is not released quickly. Furthermore, the LockFileManager is not
robust in every environment. Other -cc1 commands can stall until
timeout (after about eight minutes).
This commit changes the lock file from being necessary for correctness
to a (possibly dubious) performance hack. The remaining benefit is to
reduce duplicate work in competing -cc1 commands which depend on the
same module. Follow-up commits will change the internal build system to
continue after a timeout, and reduce the timeout. Perhaps we should
reconsider blocking at all.
This also fixes a use-after-free, when one part of a compilation
validates a PCM and starts using it, and another tries to swap out the
PCM for something new.
The PCMCache is a new type called MemoryBufferCache, which saves memory
buffers based on their filename. Its ownership is shared by the
CompilerInstance and ModuleManager.
- The ModuleManager stores PCMs there that it loads from disk, never
touching the disk if the cache is hot.
- When modules fail to validate, they're removed from the cache.
- When a CompilerInstance is spawned to build a new module, each
already-loaded PCM is assumed to be valid, and is frozen to avoid
the use-after-free.
- Any newly-built module is written directly to the cache to avoid the
round-trip to the filesystem, making lock files unnecessary for
correctness.
Original patch by Manman Ren; most testcases by Adrian Prantl!
llvm-svn: 298278
2017-03-21 01:58:26 +08:00
|
|
|
AST->PCMCache = new MemoryBufferCache;
|
2017-01-06 09:04:46 +08:00
|
|
|
AST->HSOpts = std::make_shared<HeaderSearchOptions>();
|
2015-07-17 09:19:54 +08:00
|
|
|
AST->HSOpts->ModuleFormat = PCHContainerRdr.getFormat();
|
2012-10-25 00:19:39 +08:00
|
|
|
AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts,
|
Use the same SourceManager for ModuleMaps and compilations.
This allows using virtual file mappings on the original SourceManager to
map in virtual module.map files. Without this patch, the ModuleMap
search will find a module.map file (as the FileEntry exists in the
FileManager), but will be unable to get the content from the
SourceManager (as ModuleMap previously created its own SourceManager).
Two problems needed to be fixed which this patch exposed:
1. Storing the inferred module map
When writing out a module, the ASTWriter stores the names of the files
in the main source manager; when loading the AST again, the ASTReader
errs out if such a file is found missing, unless it is overridden.
Previously CompilerInstance's compileModule method would store the
inferred module map to a temporary file; the problem with this approach
is that now that the module map is handled by the main source manager,
the ASTWriter stores the name of the temporary module map as source to
the compilation; later, when the module is loaded, the temporary file
has already been deleted, which leads to a compilation error. This patch
changes the inferred module map to instead inject a virtual file into
the source manager. This both saves some disk IO, and works with how the
ASTWriter/ASTReader handle overridden source files.
2. Changing test input in test/Modules/Inputs/*
Now that the module map file is handled by the main source manager, the
VerifyDiagnosticConsumer will not ignore diagnostics created while
parsing the module map file. The module test test/Modules/renamed.m uses
-I test/Modules/Inputs and triggers recursive loading of all module maps
in test/Modules/Inputs, some of which had conflicting names, thus
leading errors while parsing the module maps. Those diagnostics already
occur on trunk, but before this patch they would not break the test, as
they were ignored by the VerifyDiagnosticConsumer. This patch thus
changes the module maps that have been recently introduced which broke
the invariant of compatible modules maps in test/Modules/Inputs.
llvm-svn: 193314
2013-10-24 15:51:24 +08:00
|
|
|
AST->getSourceManager(),
|
2011-12-31 12:05:44 +08:00
|
|
|
AST->getDiagnostics(),
|
2017-06-06 02:10:11 +08:00
|
|
|
AST->getLangOpts(),
|
2014-05-22 12:46:25 +08:00
|
|
|
/*Target=*/nullptr));
|
2017-06-06 08:32:01 +08:00
|
|
|
AST->PPOpts = std::make_shared<PreprocessorOptions>();
|
2014-02-08 08:38:15 +08:00
|
|
|
|
2015-02-07 02:36:04 +08:00
|
|
|
for (const auto &RemappedFile : RemappedFiles)
|
2017-06-06 08:32:01 +08:00
|
|
|
AST->PPOpts->addRemappedFile(RemappedFile.first, RemappedFile.second);
|
2014-02-08 08:38:15 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// Gather Info for preprocessor construction later on.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-08-11 03:08:04 +08:00
|
|
|
HeaderSearch &HeaderInfo = *AST->HeaderInfo;
|
2009-06-20 16:08:23 +08:00
|
|
|
unsigned Counter;
|
|
|
|
|
2017-01-06 03:48:07 +08:00
|
|
|
AST->PP = std::make_shared<Preprocessor>(
|
2017-06-06 08:32:01 +08:00
|
|
|
AST->PPOpts, AST->getDiagnostics(), *AST->LangOpts,
|
2017-06-10 03:22:32 +08:00
|
|
|
AST->getSourceManager(), *AST->PCMCache, HeaderInfo, AST->ModuleLoader,
|
2017-01-06 03:48:07 +08:00
|
|
|
/*IILookup=*/nullptr,
|
|
|
|
/*OwnsHeaderSearch=*/false);
|
2011-09-02 08:18:52 +08:00
|
|
|
Preprocessor &PP = *AST->PP;
|
|
|
|
|
2017-06-30 07:23:46 +08:00
|
|
|
if (ToLoad >= LoadASTOnly)
|
|
|
|
AST->Ctx = new ASTContext(*AST->LangOpts, AST->getSourceManager(),
|
|
|
|
PP.getIdentifierTable(), PP.getSelectorTable(),
|
|
|
|
PP.getBuiltinInfo());
|
2011-09-02 07:39:15 +08:00
|
|
|
|
2012-09-15 09:10:20 +08:00
|
|
|
bool disableValid = false;
|
|
|
|
if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION"))
|
|
|
|
disableValid = true;
|
2017-06-30 07:23:46 +08:00
|
|
|
AST->Reader = new ASTReader(PP, AST->Ctx.get(), PCHContainerRdr, { },
|
2015-06-21 02:53:08 +08:00
|
|
|
/*isysroot=*/"",
|
|
|
|
/*DisableValidation=*/disableValid,
|
|
|
|
AllowPCHWithCompilerErrors);
|
2011-05-05 07:27:12 +08:00
|
|
|
|
2014-08-11 00:54:39 +08:00
|
|
|
AST->Reader->setListener(llvm::make_unique<ASTInfoCollector>(
|
2017-06-30 07:23:46 +08:00
|
|
|
*AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts,
|
2017-06-06 08:32:01 +08:00
|
|
|
AST->TargetOpts, AST->Target, Counter));
|
2009-09-03 13:59:35 +08:00
|
|
|
|
2015-03-03 16:04:19 +08:00
|
|
|
// Attach the AST reader to the AST context as an external AST
|
|
|
|
// source, so that declarations will be deserialized from the
|
|
|
|
// AST file as needed.
|
|
|
|
// We need the external source to be set up before we read the AST, because
|
|
|
|
// eagerly-deserialized declarations may use it.
|
2017-06-30 07:23:46 +08:00
|
|
|
if (AST->Ctx)
|
|
|
|
AST->Ctx->setExternalSource(AST->Reader);
|
2015-03-03 16:04:19 +08:00
|
|
|
|
2014-02-27 12:11:59 +08:00
|
|
|
switch (AST->Reader->ReadAST(Filename, serialization::MK_MainFile,
|
2012-11-16 02:57:22 +08:00
|
|
|
SourceLocation(), ASTReader::ARR_None)) {
|
2010-08-19 07:56:43 +08:00
|
|
|
case ASTReader::Success:
|
2009-06-20 16:08:23 +08:00
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:56:43 +08:00
|
|
|
case ASTReader::Failure:
|
2013-03-19 08:28:20 +08:00
|
|
|
case ASTReader::Missing:
|
2012-10-23 06:50:17 +08:00
|
|
|
case ASTReader::OutOfDate:
|
|
|
|
case ASTReader::VersionMismatch:
|
|
|
|
case ASTReader::ConfigurationMismatch:
|
|
|
|
case ASTReader::HadErrors:
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch);
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2009-06-20 16:08:23 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-02-27 12:11:59 +08:00
|
|
|
AST->OriginalSourceFile = AST->Reader->getOriginalSourceFile();
|
2009-12-02 16:44:16 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
PP.setCounterValue(Counter);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-13 11:15:25 +08:00
|
|
|
// Create an AST consumer, even though it isn't used.
|
2017-06-30 07:23:46 +08:00
|
|
|
if (ToLoad >= LoadASTOnly)
|
|
|
|
AST->Consumer.reset(new ASTConsumer);
|
|
|
|
|
2010-08-19 07:56:43 +08:00
|
|
|
// Create a semantic analysis object and tell the AST reader about it.
|
2017-06-30 07:23:46 +08:00
|
|
|
if (ToLoad >= LoadEverything) {
|
|
|
|
AST->TheSema.reset(new Sema(PP, *AST->Ctx, *AST->Consumer));
|
|
|
|
AST->TheSema->Initialize();
|
|
|
|
AST->Reader->InitializeSema(*AST->TheSema);
|
|
|
|
}
|
2010-08-13 11:15:25 +08:00
|
|
|
|
2013-05-04 06:58:43 +08:00
|
|
|
// Tell the diagnostic client that we have started a source file.
|
2017-06-30 07:23:46 +08:00
|
|
|
AST->getDiagnostics().getClient()->BeginSourceFile(PP.getLangOpts(), &PP);
|
2013-05-04 06:58:43 +08:00
|
|
|
|
2014-08-11 03:08:04 +08:00
|
|
|
return AST;
|
2009-06-20 16:08:23 +08:00
|
|
|
}
|
2009-12-01 17:51:01 +08:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
/// \brief Add the given macro to the hash of all top-level entities.
|
|
|
|
void AddDefinedMacroToHash(const Token &MacroNameTok, unsigned &Hash) {
|
2018-02-26 23:16:42 +08:00
|
|
|
Hash = llvm::djbHash(MacroNameTok.getIdentifierInfo()->getName(), Hash);
|
2017-06-21 18:24:58 +08:00
|
|
|
}
|
|
|
|
|
2018-02-26 23:16:42 +08:00
|
|
|
/// \brief Preprocessor callback class that updates a hash value with the names
|
2011-02-17 02:16:54 +08:00
|
|
|
/// of all macros that have been defined by the translation unit.
|
|
|
|
class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
|
|
|
|
unsigned &Hash;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-02-17 02:16:54 +08:00
|
|
|
public:
|
|
|
|
explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { }
|
2014-03-13 14:07:04 +08:00
|
|
|
|
|
|
|
void MacroDefined(const Token &MacroNameTok,
|
|
|
|
const MacroDirective *MD) override {
|
2017-06-21 18:24:58 +08:00
|
|
|
AddDefinedMacroToHash(MacroNameTok, Hash);
|
2011-02-17 02:16:54 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// \brief Add the given declaration to the hash of all top-level entities.
|
|
|
|
void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
|
|
|
|
if (!D)
|
|
|
|
return;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-02-17 02:16:54 +08:00
|
|
|
DeclContext *DC = D->getDeclContext();
|
|
|
|
if (!DC)
|
|
|
|
return;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-02-17 02:16:54 +08:00
|
|
|
if (!(DC->isTranslationUnit() || DC->getLookupParent()->isTranslationUnit()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
|
2013-10-16 01:37:55 +08:00
|
|
|
if (EnumDecl *EnumD = dyn_cast<EnumDecl>(D)) {
|
|
|
|
// For an unscoped enum include the enumerators in the hash since they
|
|
|
|
// enter the top-level namespace.
|
|
|
|
if (!EnumD->isScoped()) {
|
2014-03-09 02:45:14 +08:00
|
|
|
for (const auto *EI : EnumD->enumerators()) {
|
|
|
|
if (EI->getIdentifier())
|
2018-02-26 23:16:42 +08:00
|
|
|
Hash = llvm::djbHash(EI->getIdentifier()->getName(), Hash);
|
2013-10-16 01:37:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-17 02:16:54 +08:00
|
|
|
if (ND->getIdentifier())
|
2018-02-26 23:16:42 +08:00
|
|
|
Hash = llvm::djbHash(ND->getIdentifier()->getName(), Hash);
|
2011-02-17 02:16:54 +08:00
|
|
|
else if (DeclarationName Name = ND->getDeclName()) {
|
|
|
|
std::string NameStr = Name.getAsString();
|
2018-02-26 23:16:42 +08:00
|
|
|
Hash = llvm::djbHash(NameStr, Hash);
|
2011-02-17 02:16:54 +08:00
|
|
|
}
|
|
|
|
return;
|
2013-06-25 05:19:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ImportDecl *ImportD = dyn_cast<ImportDecl>(D)) {
|
|
|
|
if (Module *Mod = ImportD->getImportedModule()) {
|
|
|
|
std::string ModName = Mod->getFullModuleName();
|
2018-02-26 23:16:42 +08:00
|
|
|
Hash = llvm::djbHash(ModName, Hash);
|
2013-06-25 05:19:12 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2011-02-17 02:16:54 +08:00
|
|
|
}
|
|
|
|
|
2009-12-04 16:17:33 +08:00
|
|
|
class TopLevelDeclTrackerConsumer : public ASTConsumer {
|
|
|
|
ASTUnit &Unit;
|
2011-02-17 02:16:54 +08:00
|
|
|
unsigned &Hash;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2009-12-04 16:17:33 +08:00
|
|
|
public:
|
2011-02-17 02:16:54 +08:00
|
|
|
TopLevelDeclTrackerConsumer(ASTUnit &_Unit, unsigned &Hash)
|
|
|
|
: Unit(_Unit), Hash(Hash) {
|
|
|
|
Hash = 0;
|
|
|
|
}
|
|
|
|
|
2011-10-31 15:19:59 +08:00
|
|
|
void handleTopLevelDecl(Decl *D) {
|
2011-11-16 10:35:10 +08:00
|
|
|
if (!D)
|
|
|
|
return;
|
|
|
|
|
2011-10-31 15:19:59 +08:00
|
|
|
// FIXME: Currently ObjC method declarations are incorrectly being
|
|
|
|
// reported as top-level declarations, even though their DeclContext
|
|
|
|
// is the containing ObjC @interface/@implementation. This is a
|
|
|
|
// fundamental problem in the parser right now.
|
|
|
|
if (isa<ObjCMethodDecl>(D))
|
|
|
|
return;
|
|
|
|
|
|
|
|
AddTopLevelDeclarationToHash(D, Hash);
|
|
|
|
Unit.addTopLevelDecl(D);
|
|
|
|
|
|
|
|
handleFileLevelDecl(D);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleFileLevelDecl(Decl *D) {
|
|
|
|
Unit.addFileLevelDecl(D);
|
|
|
|
if (NamespaceDecl *NSD = dyn_cast<NamespaceDecl>(D)) {
|
2014-03-08 03:56:05 +08:00
|
|
|
for (auto *I : NSD->decls())
|
|
|
|
handleFileLevelDecl(I);
|
2010-05-04 04:16:35 +08:00
|
|
|
}
|
2009-12-04 16:17:33 +08:00
|
|
|
}
|
2010-08-12 02:52:41 +08:00
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
bool HandleTopLevelDecl(DeclGroupRef D) override {
|
2015-02-07 02:36:04 +08:00
|
|
|
for (Decl *TopLevelDecl : D)
|
|
|
|
handleTopLevelDecl(TopLevelDecl);
|
2011-11-18 08:26:59 +08:00
|
|
|
return true;
|
2011-10-31 15:19:59 +08:00
|
|
|
}
|
|
|
|
|
2010-08-12 02:52:41 +08:00
|
|
|
// We're not interested in "interesting" decls.
|
2014-03-13 14:07:04 +08:00
|
|
|
void HandleInterestingDecl(DeclGroupRef) override {}
|
2011-10-31 15:19:59 +08:00
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override {
|
2015-02-07 02:36:04 +08:00
|
|
|
for (Decl *TopLevelDecl : D)
|
|
|
|
handleTopLevelDecl(TopLevelDecl);
|
2011-10-31 15:19:59 +08:00
|
|
|
}
|
2012-10-12 00:05:00 +08:00
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
ASTMutationListener *GetASTMutationListener() override {
|
2013-05-10 09:28:51 +08:00
|
|
|
return Unit.getASTMutationListener();
|
|
|
|
}
|
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
ASTDeserializationListener *GetASTDeserializationListener() override {
|
2012-10-12 00:05:00 +08:00
|
|
|
return Unit.getDeserializationListener();
|
|
|
|
}
|
2009-12-04 16:17:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class TopLevelDeclTrackerAction : public ASTFrontendAction {
|
|
|
|
public:
|
|
|
|
ASTUnit &Unit;
|
|
|
|
|
2014-08-11 03:56:51 +08:00
|
|
|
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
|
|
|
StringRef InFile) override {
|
2011-02-17 02:16:54 +08:00
|
|
|
CI.getPreprocessor().addPPCallbacks(
|
2014-09-10 12:53:53 +08:00
|
|
|
llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
|
|
|
|
Unit.getCurrentTopLevelHashValue()));
|
2014-08-11 03:56:51 +08:00
|
|
|
return llvm::make_unique<TopLevelDeclTrackerConsumer>(
|
|
|
|
Unit, Unit.getCurrentTopLevelHashValue());
|
2009-12-01 17:51:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2009-12-04 16:17:33 +08:00
|
|
|
TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {}
|
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
bool hasCodeCompletionSupport() const override { return false; }
|
|
|
|
TranslationUnitKind getTranslationUnitKind() override {
|
2018-02-26 23:16:42 +08:00
|
|
|
return Unit.getTranslationUnitKind();
|
2010-08-10 04:45:32 +08:00
|
|
|
}
|
2009-12-01 17:51:01 +08:00
|
|
|
};
|
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
class ASTUnitPreambleCallbacks : public PreambleCallbacks {
|
2013-06-11 21:07:19 +08:00
|
|
|
public:
|
2017-06-21 18:24:58 +08:00
|
|
|
unsigned getHash() const { return Hash; }
|
2013-06-11 21:07:19 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
std::vector<Decl *> takeTopLevelDecls() { return std::move(TopLevelDecls); }
|
2013-06-11 21:07:19 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
|
|
|
|
return std::move(TopLevelDeclIDs);
|
|
|
|
}
|
2013-06-11 21:07:19 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
void AfterPCHEmitted(ASTWriter &Writer) override {
|
|
|
|
TopLevelDeclIDs.reserve(TopLevelDecls.size());
|
|
|
|
for (Decl *D : TopLevelDecls) {
|
|
|
|
// Invalid top-level decls may not have been serialized.
|
|
|
|
if (D->isInvalidDecl())
|
|
|
|
continue;
|
|
|
|
TopLevelDeclIDs.push_back(Writer.getDeclID(D));
|
|
|
|
}
|
2011-02-17 02:16:54 +08:00
|
|
|
}
|
2010-08-03 16:14:03 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
void HandleTopLevelDecl(DeclGroupRef DG) override {
|
2015-02-07 02:58:04 +08:00
|
|
|
for (Decl *D : DG) {
|
2010-08-03 16:14:03 +08:00
|
|
|
// FIXME: Currently ObjC method declarations are incorrectly being
|
|
|
|
// reported as top-level declarations, even though their DeclContext
|
|
|
|
// is the containing ObjC @interface/@implementation. This is a
|
|
|
|
// fundamental problem in the parser right now.
|
|
|
|
if (isa<ObjCMethodDecl>(D))
|
|
|
|
continue;
|
2011-02-17 02:16:54 +08:00
|
|
|
AddTopLevelDeclarationToHash(D, Hash);
|
2010-08-04 03:06:41 +08:00
|
|
|
TopLevelDecls.push_back(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-15 19:27:51 +08:00
|
|
|
std::unique_ptr<PPCallbacks> createPPCallbacks() override {
|
|
|
|
return llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(Hash);
|
2010-08-03 16:14:03 +08:00
|
|
|
}
|
2017-06-21 18:24:58 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
unsigned Hash = 0;
|
|
|
|
std::vector<Decl *> TopLevelDecls;
|
|
|
|
std::vector<serialization::DeclID> TopLevelDeclIDs;
|
|
|
|
llvm::SmallVector<ASTUnit::StandaloneDiagnostic, 4> PreambleDiags;
|
2010-08-03 16:14:03 +08:00
|
|
|
};
|
|
|
|
|
2015-10-07 07:40:43 +08:00
|
|
|
} // anonymous namespace
|
2010-08-03 16:14:03 +08:00
|
|
|
|
2013-05-05 20:39:28 +08:00
|
|
|
static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) {
|
|
|
|
return StoredDiag.getLocation().isValid();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
checkAndRemoveNonDriverDiags(SmallVectorImpl<StoredDiagnostic> &StoredDiags) {
|
2012-02-02 03:54:02 +08:00
|
|
|
// Get rid of stored diagnostics except the ones from the driver which do not
|
|
|
|
// have a source location.
|
2013-05-05 20:39:28 +08:00
|
|
|
StoredDiags.erase(
|
|
|
|
std::remove_if(StoredDiags.begin(), StoredDiags.end(), isNonDriverDiag),
|
|
|
|
StoredDiags.end());
|
2012-02-02 03:54:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> &
|
|
|
|
StoredDiagnostics,
|
|
|
|
SourceManager &SM) {
|
|
|
|
// The stored diagnostic has the old source manager in it; update
|
|
|
|
// the locations to refer into the new source manager. Since we've
|
|
|
|
// been careful to make sure that the source manager's state
|
|
|
|
// before and after are identical, so that we can reuse the source
|
|
|
|
// location itself.
|
2015-02-07 02:36:04 +08:00
|
|
|
for (StoredDiagnostic &SD : StoredDiagnostics) {
|
|
|
|
if (SD.getLocation().isValid()) {
|
|
|
|
FullSourceLoc Loc(SD.getLocation(), SM);
|
|
|
|
SD.setLocation(Loc);
|
2012-02-02 03:54:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
/// Parse the source file into a translation unit using the given compiler
|
|
|
|
/// invocation, replacing the current translation unit.
|
|
|
|
///
|
|
|
|
/// \returns True if a failure occurred that causes the ASTUnit not to
|
|
|
|
/// contain any translation-unit information, false otherwise.
|
2015-06-21 02:53:08 +08:00
|
|
|
bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
2017-05-23 19:37:52 +08:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer,
|
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
2014-08-19 00:23:45 +08:00
|
|
|
if (!Invocation)
|
2010-07-20 05:46:24 +08:00
|
|
|
return true;
|
2014-08-19 00:23:45 +08:00
|
|
|
|
2017-11-17 00:25:01 +08:00
|
|
|
auto CCInvocation = std::make_shared<CompilerInvocation>(*Invocation);
|
|
|
|
if (OverrideMainBuffer) {
|
|
|
|
assert(Preamble &&
|
|
|
|
"No preamble was built, but OverrideMainBuffer is not null");
|
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> OldVFS = VFS;
|
|
|
|
Preamble->AddImplicitPreamble(*CCInvocation, VFS, OverrideMainBuffer.get());
|
|
|
|
if (OldVFS != VFS && FileMgr) {
|
|
|
|
assert(OldVFS == FileMgr->getVirtualFileSystem() &&
|
|
|
|
"VFS passed to Parse and VFS in FileMgr are different");
|
|
|
|
FileMgr = new FileManager(FileMgr->getFileSystemOpts(), VFS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the compiler instance to use for building the AST.
|
2015-06-21 02:53:08 +08:00
|
|
|
std::unique_ptr<CompilerInstance> Clang(
|
2016-06-13 04:05:23 +08:00
|
|
|
new CompilerInstance(std::move(PCHContainerOps)));
|
2017-05-23 19:37:52 +08:00
|
|
|
if (FileMgr && VFS) {
|
|
|
|
assert(VFS == FileMgr->getVirtualFileSystem() &&
|
|
|
|
"VFS passed to Parse and VFS in FileMgr are different");
|
|
|
|
} else if (VFS) {
|
|
|
|
Clang->setVirtualFileSystem(VFS);
|
|
|
|
}
|
2011-03-22 02:40:07 +08:00
|
|
|
|
|
|
|
// Recover resources if we crash before exiting this method.
|
2011-03-22 09:15:24 +08:00
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
|
|
|
|
CICleanup(Clang.get());
|
2011-03-22 02:40:07 +08:00
|
|
|
|
2017-11-17 00:25:01 +08:00
|
|
|
Clang->setInvocation(CCInvocation);
|
2012-11-10 03:40:39 +08:00
|
|
|
OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Set up diagnostics, capturing any diagnostics that would
|
|
|
|
// otherwise be dropped.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setDiagnostics(&getDiagnostics());
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the target instance.
|
2014-07-06 13:26:44 +08:00
|
|
|
Clang->setTarget(TargetInfo::CreateTargetInfo(
|
2016-04-09 00:52:00 +08:00
|
|
|
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
|
2014-08-19 00:23:45 +08:00
|
|
|
if (!Clang->hasTarget())
|
2010-07-20 05:46:24 +08:00
|
|
|
return true;
|
2010-08-19 09:33:06 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Inform the target of the language options.
|
|
|
|
//
|
|
|
|
// FIXME: We shouldn't need to do this, the target should be immutable once
|
|
|
|
// created. This complexity should be lifted elsewhere.
|
2014-07-06 13:14:24 +08:00
|
|
|
Clang->getTarget().adjust(Clang->getLangOpts());
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-03-22 02:40:07 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
|
2009-12-01 17:51:01 +08:00
|
|
|
"Invocation must have exactly one source file!");
|
2017-04-27 02:57:40 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
|
|
|
|
InputKind::Source &&
|
2009-12-01 17:51:01 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2017-04-27 02:57:40 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
|
|
|
|
InputKind::LLVM_IR &&
|
2010-06-08 07:26:47 +08:00
|
|
|
"IR inputs not support here!");
|
2009-12-01 17:51:01 +08:00
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
// Configure the various subsystems.
|
2014-07-06 13:26:07 +08:00
|
|
|
LangOpts = Clang->getInvocation().LangOpts;
|
2011-03-22 02:40:07 +08:00
|
|
|
FileSystemOpts = Clang->getFileSystemOpts();
|
2015-10-06 22:45:20 +08:00
|
|
|
if (!FileMgr) {
|
|
|
|
Clang->createFileManager();
|
|
|
|
FileMgr = &Clang->getFileManager();
|
|
|
|
}
|
2014-05-22 12:46:25 +08:00
|
|
|
|
2017-05-30 22:25:54 +08:00
|
|
|
ResetForParse();
|
2010-08-03 04:51:39 +08:00
|
|
|
|
2017-05-30 22:25:54 +08:00
|
|
|
SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
|
|
|
|
UserFilesAreVolatile);
|
2010-08-20 08:02:33 +08:00
|
|
|
if (!OverrideMainBuffer) {
|
2012-02-02 03:54:02 +08:00
|
|
|
checkAndRemoveNonDriverDiags(StoredDiagnostics);
|
2010-08-20 08:02:33 +08:00
|
|
|
TopLevelDeclsInPreamble.clear();
|
|
|
|
}
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create a file manager object to provide access to and cache the filesystem.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setFileManager(&getFileManager());
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the source manager.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setSourceManager(&getSourceManager());
|
2018-02-26 23:16:42 +08:00
|
|
|
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-27 05:36:20 +08:00
|
|
|
// If the main file has been overridden due to the use of a preamble,
|
|
|
|
// make that override happen and introduce the preamble.
|
|
|
|
if (OverrideMainBuffer) {
|
2010-08-03 04:51:39 +08:00
|
|
|
// The stored diagnostic has the old source manager in it; update
|
|
|
|
// the locations to refer into the new source manager. Since we've
|
|
|
|
// been careful to make sure that the source manager's state
|
|
|
|
// before and after are identical, so that we can reuse the source
|
|
|
|
// location itself.
|
2012-02-02 03:54:02 +08:00
|
|
|
checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
|
2010-10-12 08:50:20 +08:00
|
|
|
|
|
|
|
// Keep track of the override buffer;
|
2014-08-19 00:23:45 +08:00
|
|
|
SavedMainFileBuffer = std::move(OverrideMainBuffer);
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-27 05:36:20 +08:00
|
|
|
}
|
2014-03-08 04:03:18 +08:00
|
|
|
|
|
|
|
std::unique_ptr<TopLevelDeclTrackerAction> Act(
|
|
|
|
new TopLevelDeclTrackerAction(*this));
|
|
|
|
|
2011-03-22 09:15:24 +08:00
|
|
|
// Recover resources if we crash before exiting this method.
|
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction>
|
|
|
|
ActCleanup(Act.get());
|
|
|
|
|
2012-01-21 00:28:04 +08:00
|
|
|
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
|
2009-12-01 17:51:01 +08:00
|
|
|
goto error;
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
|
2016-03-26 05:46:44 +08:00
|
|
|
if (SavedMainFileBuffer)
|
2014-02-28 15:11:01 +08:00
|
|
|
TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
|
|
|
|
PreambleDiagnostics, StoredDiagnostics);
|
2017-06-09 16:29:58 +08:00
|
|
|
else
|
|
|
|
PreambleSrcLocCache.clear();
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
|
2012-06-08 13:48:06 +08:00
|
|
|
if (!Act->Execute())
|
|
|
|
goto error;
|
2012-04-11 10:11:16 +08:00
|
|
|
|
|
|
|
transferASTDataFromCompilerInstance(*Clang);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2009-12-04 16:17:33 +08:00
|
|
|
Act->EndSourceFile();
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-27 05:36:20 +08:00
|
|
|
|
2012-04-11 10:11:16 +08:00
|
|
|
FailedParseDiagnostics.clear();
|
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
return false;
|
2011-03-22 02:40:17 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
error:
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-27 05:36:20 +08:00
|
|
|
// Remove the overridden buffer we used for the preamble.
|
2014-08-19 00:23:45 +08:00
|
|
|
SavedMainFileBuffer = nullptr;
|
2012-04-11 10:11:16 +08:00
|
|
|
|
|
|
|
// Keep the ownership of the data in the ASTUnit because the client may
|
|
|
|
// want to see the diagnostics.
|
|
|
|
transferASTDataFromCompilerInstance(*Clang);
|
|
|
|
FailedParseDiagnostics.swap(StoredDiagnostics);
|
2010-10-13 00:25:54 +08:00
|
|
|
StoredDiagnostics.clear();
|
2011-10-25 01:25:20 +08:00
|
|
|
NumStoredDiagnosticsFromDriver = 0;
|
2010-07-20 05:46:24 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-02-28 15:11:01 +08:00
|
|
|
static std::pair<unsigned, unsigned>
|
|
|
|
makeStandaloneRange(CharSourceRange Range, const SourceManager &SM,
|
|
|
|
const LangOptions &LangOpts) {
|
|
|
|
CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts);
|
|
|
|
unsigned Offset = SM.getFileOffset(FileRange.getBegin());
|
|
|
|
unsigned EndOffset = SM.getFileOffset(FileRange.getEnd());
|
|
|
|
return std::make_pair(Offset, EndOffset);
|
|
|
|
}
|
|
|
|
|
2014-10-04 02:52:54 +08:00
|
|
|
static ASTUnit::StandaloneFixIt makeStandaloneFixIt(const SourceManager &SM,
|
|
|
|
const LangOptions &LangOpts,
|
|
|
|
const FixItHint &InFix) {
|
|
|
|
ASTUnit::StandaloneFixIt OutFix;
|
2014-02-28 15:11:01 +08:00
|
|
|
OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts);
|
|
|
|
OutFix.InsertFromRange = makeStandaloneRange(InFix.InsertFromRange, SM,
|
|
|
|
LangOpts);
|
|
|
|
OutFix.CodeToInsert = InFix.CodeToInsert;
|
|
|
|
OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions;
|
2014-10-04 02:52:54 +08:00
|
|
|
return OutFix;
|
2014-02-28 15:11:01 +08:00
|
|
|
}
|
|
|
|
|
2014-10-04 02:52:54 +08:00
|
|
|
static ASTUnit::StandaloneDiagnostic
|
|
|
|
makeStandaloneDiagnostic(const LangOptions &LangOpts,
|
|
|
|
const StoredDiagnostic &InDiag) {
|
|
|
|
ASTUnit::StandaloneDiagnostic OutDiag;
|
2014-02-28 15:11:01 +08:00
|
|
|
OutDiag.ID = InDiag.getID();
|
|
|
|
OutDiag.Level = InDiag.getLevel();
|
|
|
|
OutDiag.Message = InDiag.getMessage();
|
|
|
|
OutDiag.LocOffset = 0;
|
|
|
|
if (InDiag.getLocation().isInvalid())
|
2014-10-04 02:52:54 +08:00
|
|
|
return OutDiag;
|
2014-02-28 15:11:01 +08:00
|
|
|
const SourceManager &SM = InDiag.getLocation().getManager();
|
|
|
|
SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation());
|
|
|
|
OutDiag.Filename = SM.getFilename(FileLoc);
|
|
|
|
if (OutDiag.Filename.empty())
|
2014-10-04 02:52:54 +08:00
|
|
|
return OutDiag;
|
2014-02-28 15:11:01 +08:00
|
|
|
OutDiag.LocOffset = SM.getFileOffset(FileLoc);
|
2015-02-07 02:36:04 +08:00
|
|
|
for (const CharSourceRange &Range : InDiag.getRanges())
|
|
|
|
OutDiag.Ranges.push_back(makeStandaloneRange(Range, SM, LangOpts));
|
|
|
|
for (const FixItHint &FixIt : InDiag.getFixIts())
|
|
|
|
OutDiag.FixIts.push_back(makeStandaloneFixIt(SM, LangOpts, FixIt));
|
2014-10-04 02:52:54 +08:00
|
|
|
|
|
|
|
return OutDiag;
|
2014-02-28 15:11:01 +08:00
|
|
|
}
|
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing
|
|
|
|
/// the source file.
|
|
|
|
///
|
|
|
|
/// This routine will compute the preamble of the main source file. If a
|
2018-02-26 23:16:42 +08:00
|
|
|
/// non-trivial preamble is found, it will precompile that preamble into a
|
2010-07-24 07:58:40 +08:00
|
|
|
/// precompiled header so that the precompiled preamble can be used to reduce
|
|
|
|
/// reparsing time. If a precompiled preamble has already been constructed,
|
2018-02-26 23:16:42 +08:00
|
|
|
/// this routine will determine if it is still valid and, if so, avoid
|
2010-07-24 07:58:40 +08:00
|
|
|
/// rebuilding the precompiled preamble.
|
|
|
|
///
|
2010-08-10 04:45:32 +08:00
|
|
|
/// \param AllowRebuild When true (the default), this routine is
|
|
|
|
/// allowed to rebuild the precompiled preamble if it is found to be
|
|
|
|
/// out-of-date.
|
|
|
|
///
|
|
|
|
/// \param MaxLines When non-zero, the maximum number of lines that
|
|
|
|
/// can occur within the preamble.
|
|
|
|
///
|
2010-07-24 08:38:13 +08:00
|
|
|
/// \returns If the precompiled preamble can be used, returns a newly-allocated
|
|
|
|
/// buffer that should be used in place of the main file when doing so.
|
|
|
|
/// Otherwise, returns a NULL pointer.
|
2014-08-19 02:47:08 +08:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer>
|
|
|
|
ASTUnit::getMainBufferWithPrecompiledPreamble(
|
2015-06-21 02:53:08 +08:00
|
|
|
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
2017-05-23 19:37:52 +08:00
|
|
|
const CompilerInvocation &PreambleInvocationIn,
|
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool AllowRebuild,
|
2014-08-19 02:47:08 +08:00
|
|
|
unsigned MaxLines) {
|
2010-08-04 13:53:38 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
auto MainFilePath =
|
|
|
|
PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile();
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> MainFileBuffer =
|
|
|
|
getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(),
|
|
|
|
MainFilePath);
|
|
|
|
if (!MainFileBuffer)
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2014-07-07 15:47:20 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
PreambleBounds Bounds =
|
|
|
|
ComputePreambleBounds(*PreambleInvocationIn.getLangOpts(),
|
|
|
|
MainFileBuffer.get(), MaxLines);
|
|
|
|
if (!Bounds.Size)
|
|
|
|
return nullptr;
|
2016-05-17 22:34:53 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
if (Preamble) {
|
|
|
|
if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds,
|
|
|
|
VFS.get())) {
|
|
|
|
// Okay! We can re-use the precompiled preamble.
|
2016-05-17 22:34:53 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
// Set the state of the diagnostic object to mimic its state
|
|
|
|
// after parsing the preamble.
|
|
|
|
getDiagnostics().Reset();
|
|
|
|
ProcessWarningOptions(getDiagnostics(),
|
|
|
|
PreambleInvocationIn.getDiagnosticOpts());
|
|
|
|
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
|
2016-05-17 22:34:53 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
PreambleRebuildCounter = 1;
|
|
|
|
return MainFileBuffer;
|
|
|
|
} else {
|
|
|
|
Preamble.reset();
|
|
|
|
PreambleDiagnostics.clear();
|
|
|
|
TopLevelDeclsInPreamble.clear();
|
|
|
|
PreambleRebuildCounter = 1;
|
2010-07-24 07:58:40 +08:00
|
|
|
}
|
2010-08-10 04:45:32 +08:00
|
|
|
}
|
2010-08-04 13:53:38 +08:00
|
|
|
|
|
|
|
// If the preamble rebuild counter > 1, it's because we previously
|
|
|
|
// failed to build a preamble and we're not yet ready to try
|
|
|
|
// again. Decrement the counter and return a failure.
|
|
|
|
if (PreambleRebuildCounter > 1) {
|
|
|
|
--PreambleRebuildCounter;
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2010-08-04 13:53:38 +08:00
|
|
|
}
|
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
assert(!Preamble && "No Preamble should be stored at that point");
|
|
|
|
// If we aren't allowed to rebuild the precompiled preamble, just
|
|
|
|
// return now.
|
|
|
|
if (!AllowRebuild)
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2011-03-22 02:40:07 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
SmallVector<StandaloneDiagnostic, 4> NewPreambleDiagsStandalone;
|
|
|
|
SmallVector<StoredDiagnostic, 4> NewPreambleDiags;
|
2017-06-21 20:34:27 +08:00
|
|
|
ASTUnitPreambleCallbacks Callbacks;
|
2017-06-21 18:24:58 +08:00
|
|
|
{
|
|
|
|
llvm::Optional<CaptureDroppedDiagnostics> Capture;
|
|
|
|
if (CaptureDiagnostics)
|
|
|
|
Capture.emplace(/*RequestCapture=*/true, *Diagnostics, &NewPreambleDiags,
|
|
|
|
&NewPreambleDiagsStandalone);
|
|
|
|
|
|
|
|
// We did not previously compute a preamble, or it can't be reused anyway.
|
|
|
|
SimpleTimer PreambleTimer(WantTiming);
|
|
|
|
PreambleTimer.setOutput("Precompiling preamble");
|
|
|
|
|
|
|
|
llvm::ErrorOr<PrecompiledPreamble> NewPreamble = PrecompiledPreamble::Build(
|
|
|
|
PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS,
|
2017-11-17 00:25:01 +08:00
|
|
|
PCHContainerOps, /*StoreInMemory=*/false, Callbacks);
|
2017-06-21 18:24:58 +08:00
|
|
|
if (NewPreamble) {
|
|
|
|
Preamble = std::move(*NewPreamble);
|
|
|
|
PreambleRebuildCounter = 1;
|
|
|
|
} else {
|
|
|
|
switch (static_cast<BuildPreambleError>(NewPreamble.getError().value())) {
|
|
|
|
case BuildPreambleError::CouldntCreateTempFile:
|
|
|
|
case BuildPreambleError::PreambleIsEmpty:
|
|
|
|
// Try again next time.
|
|
|
|
PreambleRebuildCounter = 1;
|
2017-06-21 20:34:27 +08:00
|
|
|
return nullptr;
|
2017-06-21 18:24:58 +08:00
|
|
|
case BuildPreambleError::CouldntCreateTargetInfo:
|
|
|
|
case BuildPreambleError::BeginSourceFileFailed:
|
|
|
|
case BuildPreambleError::CouldntEmitPCH:
|
|
|
|
case BuildPreambleError::CouldntCreateVFSOverlay:
|
|
|
|
// These erros are more likely to repeat, retry after some period.
|
|
|
|
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
|
2017-06-21 20:34:27 +08:00
|
|
|
return nullptr;
|
2017-06-21 18:24:58 +08:00
|
|
|
}
|
2017-06-21 20:34:27 +08:00
|
|
|
llvm_unreachable("unexpected BuildPreambleError");
|
2017-06-21 18:24:58 +08:00
|
|
|
}
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
2014-02-28 15:11:01 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
assert(Preamble && "Preamble wasn't built");
|
2014-02-28 15:11:01 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
TopLevelDecls.clear();
|
|
|
|
TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs();
|
|
|
|
PreambleTopLevelHashValue = Callbacks.getHash();
|
2014-02-28 15:11:01 +08:00
|
|
|
|
2010-08-03 04:51:39 +08:00
|
|
|
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
|
2014-07-01 04:04:14 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
checkAndRemoveNonDriverDiags(NewPreambleDiags);
|
|
|
|
StoredDiagnostics = std::move(NewPreambleDiags);
|
|
|
|
PreambleDiagnostics = std::move(NewPreambleDiagsStandalone);
|
2014-07-07 15:47:20 +08:00
|
|
|
|
2011-02-17 02:16:54 +08:00
|
|
|
// If the hash of top-level entities differs from the hash of the top-level
|
|
|
|
// entities the last time we rebuilt the preamble, clear out the completion
|
|
|
|
// cache.
|
|
|
|
if (CurrentTopLevelHashValue != PreambleTopLevelHashValue) {
|
|
|
|
CompletionCacheTopLevelHashValue = 0;
|
|
|
|
PreambleTopLevelHashValue = CurrentTopLevelHashValue;
|
|
|
|
}
|
2014-08-19 02:47:08 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
return MainFileBuffer;
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2010-08-04 03:06:41 +08:00
|
|
|
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
|
2017-06-21 18:24:58 +08:00
|
|
|
assert(Preamble && "Should only be called when preamble was built");
|
|
|
|
|
2010-08-04 03:06:41 +08:00
|
|
|
std::vector<Decl *> Resolved;
|
|
|
|
Resolved.reserve(TopLevelDeclsInPreamble.size());
|
|
|
|
ExternalASTSource &Source = *getASTContext().getExternalSource();
|
2015-02-07 02:36:04 +08:00
|
|
|
for (serialization::DeclID TopLevelDecl : TopLevelDeclsInPreamble) {
|
2010-08-04 03:06:41 +08:00
|
|
|
// Resolve the declaration ID to an actual declaration, possibly
|
|
|
|
// deserializing the declaration in the process.
|
2015-02-07 02:36:04 +08:00
|
|
|
if (Decl *D = Source.GetExternalDecl(TopLevelDecl))
|
2010-08-04 03:06:41 +08:00
|
|
|
Resolved.push_back(D);
|
|
|
|
}
|
|
|
|
TopLevelDeclsInPreamble.clear();
|
|
|
|
TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end());
|
|
|
|
}
|
|
|
|
|
2012-04-11 10:11:16 +08:00
|
|
|
void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
|
2014-04-23 01:40:12 +08:00
|
|
|
// Steal the created target, context, and preprocessor if they have been
|
|
|
|
// created.
|
|
|
|
assert(CI.hasInvocation() && "missing invocation");
|
2014-07-06 13:26:07 +08:00
|
|
|
LangOpts = CI.getInvocation().LangOpts;
|
2014-08-11 03:14:48 +08:00
|
|
|
TheSema = CI.takeSema();
|
2014-08-11 03:56:51 +08:00
|
|
|
Consumer = CI.takeASTConsumer();
|
2014-04-19 04:39:48 +08:00
|
|
|
if (CI.hasASTContext())
|
|
|
|
Ctx = &CI.getASTContext();
|
|
|
|
if (CI.hasPreprocessor())
|
2017-01-06 03:48:07 +08:00
|
|
|
PP = CI.getPreprocessorPtr();
|
2014-05-22 12:46:25 +08:00
|
|
|
CI.setSourceManager(nullptr);
|
|
|
|
CI.setFileManager(nullptr);
|
2014-04-19 04:39:48 +08:00
|
|
|
if (CI.hasTarget())
|
|
|
|
Target = &CI.getTarget();
|
2012-04-11 10:11:16 +08:00
|
|
|
Reader = CI.getModuleManager();
|
2013-05-24 13:44:08 +08:00
|
|
|
HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
|
2012-04-11 10:11:16 +08:00
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef ASTUnit::getMainFileName() const {
|
2013-01-12 06:11:14 +08:00
|
|
|
if (Invocation && !Invocation->getFrontendOpts().Inputs.empty()) {
|
|
|
|
const FrontendInputFile &Input = Invocation->getFrontendOpts().Inputs[0];
|
|
|
|
if (Input.isFile())
|
|
|
|
return Input.getFile();
|
|
|
|
else
|
|
|
|
return Input.getBuffer()->getBufferIdentifier();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SourceMgr) {
|
|
|
|
if (const FileEntry *
|
|
|
|
FE = SourceMgr->getFileEntryForID(SourceMgr->getMainFileID()))
|
|
|
|
return FE->getName();
|
|
|
|
}
|
|
|
|
|
|
|
|
return StringRef();
|
2010-10-28 23:44:59 +08:00
|
|
|
}
|
|
|
|
|
2013-03-06 04:21:14 +08:00
|
|
|
StringRef ASTUnit::getASTFileName() const {
|
|
|
|
if (!isMainFileAST())
|
|
|
|
return StringRef();
|
|
|
|
|
|
|
|
serialization::ModuleFile &
|
|
|
|
Mod = Reader->getModuleManager().getPrimaryModule();
|
|
|
|
return Mod.FileName;
|
|
|
|
}
|
|
|
|
|
2017-01-07 03:49:01 +08:00
|
|
|
std::unique_ptr<ASTUnit>
|
|
|
|
ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
|
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
|
|
|
bool CaptureDiagnostics, bool UserFilesAreVolatile) {
|
|
|
|
std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
|
2014-10-15 07:36:06 +08:00
|
|
|
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
|
2014-04-16 02:16:25 +08:00
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS =
|
|
|
|
createVFSFromCompilerInvocation(*CI, *Diags);
|
|
|
|
if (!VFS)
|
|
|
|
return nullptr;
|
2017-01-07 03:49:01 +08:00
|
|
|
AST->Diagnostics = Diags;
|
|
|
|
AST->FileSystemOpts = CI->getFileSystemOpts();
|
|
|
|
AST->Invocation = std::move(CI);
|
2014-04-16 02:16:25 +08:00
|
|
|
AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
|
2012-07-12 04:59:04 +08:00
|
|
|
AST->UserFilesAreVolatile = UserFilesAreVolatile;
|
|
|
|
AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
|
|
|
|
UserFilesAreVolatile);
|
Reapply "Modules: Cache PCMs in memory and avoid a use-after-free"
This reverts commit r298185, effectively reapplying r298165, after fixing the
new unit tests (PR32338). The memory buffer generator doesn't null-terminate
the MemoryBuffer it creates; this version of the commit informs getMemBuffer
about that to avoid the assert.
Original commit message follows:
----
Clang's internal build system for implicit modules uses lock files to
ensure that after a process writes a PCM it will read the same one back
in (without contention from other -cc1 commands). Since PCMs are read
from disk repeatedly while invalidating, building, and importing, the
lock is not released quickly. Furthermore, the LockFileManager is not
robust in every environment. Other -cc1 commands can stall until
timeout (after about eight minutes).
This commit changes the lock file from being necessary for correctness
to a (possibly dubious) performance hack. The remaining benefit is to
reduce duplicate work in competing -cc1 commands which depend on the
same module. Follow-up commits will change the internal build system to
continue after a timeout, and reduce the timeout. Perhaps we should
reconsider blocking at all.
This also fixes a use-after-free, when one part of a compilation
validates a PCM and starts using it, and another tries to swap out the
PCM for something new.
The PCMCache is a new type called MemoryBufferCache, which saves memory
buffers based on their filename. Its ownership is shared by the
CompilerInstance and ModuleManager.
- The ModuleManager stores PCMs there that it loads from disk, never
touching the disk if the cache is hot.
- When modules fail to validate, they're removed from the cache.
- When a CompilerInstance is spawned to build a new module, each
already-loaded PCM is assumed to be valid, and is frozen to avoid
the use-after-free.
- Any newly-built module is written directly to the cache to avoid the
round-trip to the filesystem, making lock files unnecessary for
correctness.
Original patch by Manman Ren; most testcases by Adrian Prantl!
llvm-svn: 298278
2017-03-21 01:58:26 +08:00
|
|
|
AST->PCMCache = new MemoryBufferCache;
|
2011-03-10 01:21:42 +08:00
|
|
|
|
2017-01-07 03:49:01 +08:00
|
|
|
return AST;
|
2011-03-10 01:21:42 +08:00
|
|
|
}
|
|
|
|
|
2014-03-08 04:03:18 +08:00
|
|
|
ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
|
2017-01-07 03:49:01 +08:00
|
|
|
std::shared_ptr<CompilerInvocation> CI,
|
2015-06-21 02:53:08 +08:00
|
|
|
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
2016-02-10 03:07:13 +08:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FrontendAction *Action,
|
2015-06-21 02:53:08 +08:00
|
|
|
ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath,
|
2015-12-15 17:30:31 +08:00
|
|
|
bool OnlyLocalDecls, bool CaptureDiagnostics,
|
|
|
|
unsigned PrecompilePreambleAfterNParses, bool CacheCodeCompletionResults,
|
|
|
|
bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile,
|
|
|
|
std::unique_ptr<ASTUnit> *ErrAST) {
|
2011-05-04 07:26:34 +08:00
|
|
|
assert(CI && "A CompilerInvocation is required");
|
|
|
|
|
2014-03-08 04:03:18 +08:00
|
|
|
std::unique_ptr<ASTUnit> OwnAST;
|
2011-10-15 05:22:05 +08:00
|
|
|
ASTUnit *AST = Unit;
|
|
|
|
if (!AST) {
|
|
|
|
// Create the AST unit.
|
2017-01-07 03:49:01 +08:00
|
|
|
OwnAST = create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile);
|
2011-10-15 05:22:05 +08:00
|
|
|
AST = OwnAST.get();
|
2014-04-16 02:16:25 +08:00
|
|
|
if (!AST)
|
|
|
|
return nullptr;
|
2011-10-15 05:22:05 +08:00
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-11-28 12:56:00 +08:00
|
|
|
if (!ResourceFilesPath.empty()) {
|
|
|
|
// Override the resources path.
|
|
|
|
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
|
|
|
|
}
|
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
2015-12-15 17:30:31 +08:00
|
|
|
if (PrecompilePreambleAfterNParses > 0)
|
|
|
|
AST->PreambleRebuildCounter = PrecompilePreambleAfterNParses;
|
2011-08-26 06:30:56 +08:00
|
|
|
AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete;
|
2011-11-28 12:56:00 +08:00
|
|
|
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
|
2012-07-03 01:35:10 +08:00
|
|
|
AST->IncludeBriefCommentsInCodeCompletion
|
|
|
|
= IncludeBriefCommentsInCodeCompletion;
|
2011-05-04 07:26:34 +08:00
|
|
|
|
|
|
|
// Recover resources if we crash before exiting this method.
|
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
|
2011-10-15 05:22:05 +08:00
|
|
|
ASTUnitCleanup(OwnAST.get());
|
2011-09-26 07:23:43 +08:00
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
|
|
|
|
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
|
2014-07-05 11:08:06 +08:00
|
|
|
DiagCleanup(Diags.get());
|
2011-05-04 07:26:34 +08:00
|
|
|
|
|
|
|
// We'll manage file buffers ourselves.
|
|
|
|
CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
|
|
|
|
CI->getFrontendOpts().DisableFree = false;
|
|
|
|
ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts());
|
|
|
|
|
|
|
|
// Create the compiler instance to use for building the AST.
|
2015-06-21 02:53:08 +08:00
|
|
|
std::unique_ptr<CompilerInstance> Clang(
|
2016-06-13 04:05:23 +08:00
|
|
|
new CompilerInstance(std::move(PCHContainerOps)));
|
2011-05-04 07:26:34 +08:00
|
|
|
|
|
|
|
// Recover resources if we crash before exiting this method.
|
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
|
|
|
|
CICleanup(Clang.get());
|
|
|
|
|
2017-01-07 03:49:01 +08:00
|
|
|
Clang->setInvocation(std::move(CI));
|
2012-11-10 03:40:39 +08:00
|
|
|
AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
// Set up diagnostics, capturing any diagnostics that would
|
|
|
|
// otherwise be dropped.
|
|
|
|
Clang->setDiagnostics(&AST->getDiagnostics());
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
// Create the target instance.
|
2014-07-06 13:26:44 +08:00
|
|
|
Clang->setTarget(TargetInfo::CreateTargetInfo(
|
2016-04-09 00:52:00 +08:00
|
|
|
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
|
2011-05-04 07:26:34 +08:00
|
|
|
if (!Clang->hasTarget())
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2011-05-04 07:26:34 +08:00
|
|
|
|
|
|
|
// Inform the target of the language options.
|
|
|
|
//
|
|
|
|
// FIXME: We shouldn't need to do this, the target should be immutable once
|
|
|
|
// created. This complexity should be lifted elsewhere.
|
2014-07-06 13:14:24 +08:00
|
|
|
Clang->getTarget().adjust(Clang->getLangOpts());
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
|
|
|
|
"Invocation must have exactly one source file!");
|
2017-04-27 02:57:40 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
|
|
|
|
InputKind::Source &&
|
2011-05-04 07:26:34 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2017-04-27 02:57:40 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
|
|
|
|
InputKind::LLVM_IR &&
|
|
|
|
"IR inputs not support here!");
|
2011-05-04 07:26:34 +08:00
|
|
|
|
|
|
|
// Configure the various subsystems.
|
|
|
|
AST->TheSema.reset();
|
2014-05-22 12:46:25 +08:00
|
|
|
AST->Ctx = nullptr;
|
|
|
|
AST->PP = nullptr;
|
|
|
|
AST->Reader = nullptr;
|
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
// Create a file manager object to provide access to and cache the filesystem.
|
|
|
|
Clang->setFileManager(&AST->getFileManager());
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
// Create the source manager.
|
|
|
|
Clang->setSourceManager(&AST->getSourceManager());
|
|
|
|
|
2016-02-10 03:07:13 +08:00
|
|
|
FrontendAction *Act = Action;
|
2011-05-04 07:26:34 +08:00
|
|
|
|
2014-03-08 04:03:18 +08:00
|
|
|
std::unique_ptr<TopLevelDeclTrackerAction> TrackerAct;
|
2011-05-04 07:26:34 +08:00
|
|
|
if (!Act) {
|
|
|
|
TrackerAct.reset(new TopLevelDeclTrackerAction(*AST));
|
|
|
|
Act = TrackerAct.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recover resources if we crash before exiting this method.
|
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction>
|
|
|
|
ActCleanup(TrackerAct.get());
|
|
|
|
|
2012-04-11 10:11:16 +08:00
|
|
|
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
|
|
|
|
AST->transferASTDataFromCompilerInstance(*Clang);
|
|
|
|
if (OwnAST && ErrAST)
|
|
|
|
ErrAST->swap(OwnAST);
|
|
|
|
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2012-04-11 10:11:16 +08:00
|
|
|
}
|
2011-11-28 12:56:00 +08:00
|
|
|
|
|
|
|
if (Persistent && !TrackerAct) {
|
|
|
|
Clang->getPreprocessor().addPPCallbacks(
|
2014-09-10 12:53:53 +08:00
|
|
|
llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
|
|
|
|
AST->getCurrentTopLevelHashValue()));
|
2014-08-11 03:56:51 +08:00
|
|
|
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
|
2011-11-28 12:56:00 +08:00
|
|
|
if (Clang->hasASTConsumer())
|
|
|
|
Consumers.push_back(Clang->takeASTConsumer());
|
2014-08-11 03:56:51 +08:00
|
|
|
Consumers.push_back(llvm::make_unique<TopLevelDeclTrackerConsumer>(
|
|
|
|
*AST, AST->getCurrentTopLevelHashValue()));
|
|
|
|
Clang->setASTConsumer(
|
|
|
|
llvm::make_unique<MultiplexConsumer>(std::move(Consumers)));
|
2011-11-28 12:56:00 +08:00
|
|
|
}
|
2012-06-08 13:48:06 +08:00
|
|
|
if (!Act->Execute()) {
|
|
|
|
AST->transferASTDataFromCompilerInstance(*Clang);
|
|
|
|
if (OwnAST && ErrAST)
|
|
|
|
ErrAST->swap(OwnAST);
|
|
|
|
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2012-06-08 13:48:06 +08:00
|
|
|
}
|
2012-04-11 10:11:16 +08:00
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
// Steal the created target, context, and preprocessor.
|
2012-04-11 10:11:16 +08:00
|
|
|
AST->transferASTDataFromCompilerInstance(*Clang);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
Act->EndSourceFile();
|
|
|
|
|
2011-10-15 05:22:05 +08:00
|
|
|
if (OwnAST)
|
2014-03-08 03:33:25 +08:00
|
|
|
return OwnAST.release();
|
2011-10-15 05:22:05 +08:00
|
|
|
else
|
|
|
|
return AST;
|
2011-05-04 07:26:34 +08:00
|
|
|
}
|
|
|
|
|
2015-06-21 02:53:08 +08:00
|
|
|
bool ASTUnit::LoadFromCompilerInvocation(
|
|
|
|
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
2017-05-23 19:37:52 +08:00
|
|
|
unsigned PrecompilePreambleAfterNParses,
|
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
2010-10-12 08:50:20 +08:00
|
|
|
if (!Invocation)
|
|
|
|
return true;
|
2017-05-23 19:37:52 +08:00
|
|
|
|
|
|
|
assert(VFS && "VFS is null");
|
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
// We'll manage file buffers ourselves.
|
|
|
|
Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
|
|
|
|
Invocation->getFrontendOpts().DisableFree = false;
|
2017-01-19 00:25:48 +08:00
|
|
|
getDiagnostics().Reset();
|
2011-01-19 09:02:47 +08:00
|
|
|
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
|
2010-10-12 08:50:20 +08:00
|
|
|
|
2014-08-19 00:23:45 +08:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
|
2015-12-15 17:30:31 +08:00
|
|
|
if (PrecompilePreambleAfterNParses > 0) {
|
|
|
|
PreambleRebuildCounter = PrecompilePreambleAfterNParses;
|
2015-06-21 02:53:08 +08:00
|
|
|
OverrideMainBuffer =
|
2017-05-23 19:37:52 +08:00
|
|
|
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
|
2017-02-14 00:16:43 +08:00
|
|
|
getDiagnostics().Reset();
|
|
|
|
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
|
2010-10-12 08:50:20 +08:00
|
|
|
}
|
2017-05-23 19:37:52 +08:00
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
SimpleTimer ParsingTimer(WantTiming);
|
2010-11-10 04:00:56 +08:00
|
|
|
ParsingTimer.setOutput("Parsing " + getMainFileName());
|
2017-05-23 19:37:52 +08:00
|
|
|
|
2011-03-22 09:15:24 +08:00
|
|
|
// Recover resources if we crash before exiting this method.
|
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
|
2014-08-19 00:23:45 +08:00
|
|
|
MemBufferCleanup(OverrideMainBuffer.get());
|
|
|
|
|
2017-05-23 19:37:52 +08:00
|
|
|
return Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
|
2010-10-12 08:50:20 +08:00
|
|
|
}
|
|
|
|
|
2014-04-26 01:01:33 +08:00
|
|
|
std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
|
2017-01-07 03:49:01 +08:00
|
|
|
std::shared_ptr<CompilerInvocation> CI,
|
2015-06-21 02:53:08 +08:00
|
|
|
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
2015-10-06 22:45:20 +08:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
|
2015-12-15 17:30:31 +08:00
|
|
|
bool OnlyLocalDecls, bool CaptureDiagnostics,
|
|
|
|
unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
|
|
|
|
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
|
|
|
|
bool UserFilesAreVolatile) {
|
2010-07-20 05:46:24 +08:00
|
|
|
// Create the AST unit.
|
2014-04-26 01:01:33 +08:00
|
|
|
std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
|
2014-10-15 07:36:06 +08:00
|
|
|
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
|
2010-07-20 05:46:24 +08:00
|
|
|
AST->Diagnostics = Diags;
|
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
2010-11-11 08:39:14 +08:00
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
2011-08-26 06:30:56 +08:00
|
|
|
AST->TUKind = TUKind;
|
2010-08-14 06:48:40 +08:00
|
|
|
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
|
2012-07-03 01:35:10 +08:00
|
|
|
AST->IncludeBriefCommentsInCodeCompletion
|
|
|
|
= IncludeBriefCommentsInCodeCompletion;
|
2017-01-07 03:49:01 +08:00
|
|
|
AST->Invocation = std::move(CI);
|
2015-10-06 22:45:20 +08:00
|
|
|
AST->FileSystemOpts = FileMgr->getFileSystemOpts();
|
|
|
|
AST->FileMgr = FileMgr;
|
2012-07-12 04:59:04 +08:00
|
|
|
AST->UserFilesAreVolatile = UserFilesAreVolatile;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-03-18 10:06:56 +08:00
|
|
|
// Recover resources if we crash before exiting this method.
|
2011-03-22 09:15:24 +08:00
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
|
|
|
|
ASTUnitCleanup(AST.get());
|
2011-09-26 07:23:43 +08:00
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
|
|
|
|
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
|
2014-07-05 11:08:06 +08:00
|
|
|
DiagCleanup(Diags.get());
|
2011-03-18 10:06:56 +08:00
|
|
|
|
2016-06-13 04:05:23 +08:00
|
|
|
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
|
2017-05-23 19:37:52 +08:00
|
|
|
PrecompilePreambleAfterNParses,
|
|
|
|
AST->FileMgr->getVirtualFileSystem()))
|
2014-04-26 01:01:33 +08:00
|
|
|
return nullptr;
|
|
|
|
return AST;
|
2009-12-01 17:51:01 +08:00
|
|
|
}
|
2009-12-02 11:23:45 +08:00
|
|
|
|
2014-03-08 04:03:18 +08:00
|
|
|
ASTUnit *ASTUnit::LoadFromCommandLine(
|
|
|
|
const char **ArgBegin, const char **ArgEnd,
|
2015-06-21 02:53:08 +08:00
|
|
|
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
2014-03-08 04:03:18 +08:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
|
|
|
|
bool OnlyLocalDecls, bool CaptureDiagnostics,
|
|
|
|
ArrayRef<RemappedFile> RemappedFiles, bool RemappedFilesKeepOriginalName,
|
2015-12-15 17:30:31 +08:00
|
|
|
unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
|
2014-03-08 04:03:18 +08:00
|
|
|
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
|
|
|
|
bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies,
|
2017-06-09 09:20:48 +08:00
|
|
|
bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization,
|
2017-05-23 19:37:52 +08:00
|
|
|
llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST,
|
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
2014-10-15 08:33:06 +08:00
|
|
|
assert(Diags.get() && "no DiagnosticsEngine was provided");
|
2009-12-02 11:23:45 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
|
2017-01-07 03:49:01 +08:00
|
|
|
|
|
|
|
std::shared_ptr<CompilerInvocation> CI;
|
2010-11-11 08:39:14 +08:00
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
{
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
|
|
|
|
&StoredDiagnostics, nullptr);
|
2010-10-12 08:50:20 +08:00
|
|
|
|
2011-04-05 07:11:45 +08:00
|
|
|
CI = clang::createInvocationFromCommandLine(
|
2017-06-28 23:06:34 +08:00
|
|
|
llvm::makeArrayRef(ArgBegin, ArgEnd), Diags, VFS);
|
2011-04-05 05:38:51 +08:00
|
|
|
if (!CI)
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2009-12-02 11:23:45 +08:00
|
|
|
}
|
2010-11-11 08:39:14 +08:00
|
|
|
|
2010-01-23 08:14:00 +08:00
|
|
|
// Override any files that need remapping
|
2015-02-07 02:36:04 +08:00
|
|
|
for (const auto &RemappedFile : RemappedFiles) {
|
|
|
|
CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first,
|
|
|
|
RemappedFile.second);
|
2011-03-05 09:03:53 +08:00
|
|
|
}
|
2012-03-07 09:51:17 +08:00
|
|
|
PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
|
|
|
|
PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
|
|
|
|
PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
|
2017-06-09 09:20:48 +08:00
|
|
|
PPOpts.SingleFileParseMode = SingleFileParse;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2009-12-15 08:06:45 +08:00
|
|
|
// Override the resources path.
|
2010-01-31 05:47:16 +08:00
|
|
|
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
|
2009-12-02 11:23:45 +08:00
|
|
|
|
2012-04-12 18:11:59 +08:00
|
|
|
CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies;
|
|
|
|
|
2015-11-20 11:36:21 +08:00
|
|
|
if (ModuleFormat)
|
|
|
|
CI->getHeaderSearchOpts().ModuleFormat = ModuleFormat.getValue();
|
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
// Create the AST unit.
|
2014-03-08 04:03:18 +08:00
|
|
|
std::unique_ptr<ASTUnit> AST;
|
2010-10-12 08:50:20 +08:00
|
|
|
AST.reset(new ASTUnit(false));
|
2014-10-15 07:36:06 +08:00
|
|
|
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
|
2010-10-12 08:50:20 +08:00
|
|
|
AST->Diagnostics = Diags;
|
2011-03-19 02:22:40 +08:00
|
|
|
AST->FileSystemOpts = CI->getFileSystemOpts();
|
2017-05-23 19:37:52 +08:00
|
|
|
if (!VFS)
|
|
|
|
VFS = vfs::getRealFileSystem();
|
|
|
|
VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
|
2014-04-16 02:16:25 +08:00
|
|
|
if (!VFS)
|
|
|
|
return nullptr;
|
|
|
|
AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
|
Reapply "Modules: Cache PCMs in memory and avoid a use-after-free"
This reverts commit r298185, effectively reapplying r298165, after fixing the
new unit tests (PR32338). The memory buffer generator doesn't null-terminate
the MemoryBuffer it creates; this version of the commit informs getMemBuffer
about that to avoid the assert.
Original commit message follows:
----
Clang's internal build system for implicit modules uses lock files to
ensure that after a process writes a PCM it will read the same one back
in (without contention from other -cc1 commands). Since PCMs are read
from disk repeatedly while invalidating, building, and importing, the
lock is not released quickly. Furthermore, the LockFileManager is not
robust in every environment. Other -cc1 commands can stall until
timeout (after about eight minutes).
This commit changes the lock file from being necessary for correctness
to a (possibly dubious) performance hack. The remaining benefit is to
reduce duplicate work in competing -cc1 commands which depend on the
same module. Follow-up commits will change the internal build system to
continue after a timeout, and reduce the timeout. Perhaps we should
reconsider blocking at all.
This also fixes a use-after-free, when one part of a compilation
validates a PCM and starts using it, and another tries to swap out the
PCM for something new.
The PCMCache is a new type called MemoryBufferCache, which saves memory
buffers based on their filename. Its ownership is shared by the
CompilerInstance and ModuleManager.
- The ModuleManager stores PCMs there that it loads from disk, never
touching the disk if the cache is hot.
- When modules fail to validate, they're removed from the cache.
- When a CompilerInstance is spawned to build a new module, each
already-loaded PCM is assumed to be valid, and is frozen to avoid
the use-after-free.
- Any newly-built module is written directly to the cache to avoid the
round-trip to the filesystem, making lock files unnecessary for
correctness.
Original patch by Manman Ren; most testcases by Adrian Prantl!
llvm-svn: 298278
2017-03-21 01:58:26 +08:00
|
|
|
AST->PCMCache = new MemoryBufferCache;
|
2010-10-12 08:50:20 +08:00
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
2010-11-11 08:39:14 +08:00
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
2011-08-26 06:30:56 +08:00
|
|
|
AST->TUKind = TUKind;
|
2010-10-12 08:50:20 +08:00
|
|
|
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
|
2012-07-03 01:35:10 +08:00
|
|
|
AST->IncludeBriefCommentsInCodeCompletion
|
|
|
|
= IncludeBriefCommentsInCodeCompletion;
|
2012-07-12 04:59:04 +08:00
|
|
|
AST->UserFilesAreVolatile = UserFilesAreVolatile;
|
2010-10-12 08:50:20 +08:00
|
|
|
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
|
|
|
|
AST->StoredDiagnostics.swap(StoredDiagnostics);
|
2011-03-22 02:40:17 +08:00
|
|
|
AST->Invocation = CI;
|
2012-10-12 00:05:00 +08:00
|
|
|
if (ForSerialization)
|
Reapply "Modules: Cache PCMs in memory and avoid a use-after-free"
This reverts commit r298185, effectively reapplying r298165, after fixing the
new unit tests (PR32338). The memory buffer generator doesn't null-terminate
the MemoryBuffer it creates; this version of the commit informs getMemBuffer
about that to avoid the assert.
Original commit message follows:
----
Clang's internal build system for implicit modules uses lock files to
ensure that after a process writes a PCM it will read the same one back
in (without contention from other -cc1 commands). Since PCMs are read
from disk repeatedly while invalidating, building, and importing, the
lock is not released quickly. Furthermore, the LockFileManager is not
robust in every environment. Other -cc1 commands can stall until
timeout (after about eight minutes).
This commit changes the lock file from being necessary for correctness
to a (possibly dubious) performance hack. The remaining benefit is to
reduce duplicate work in competing -cc1 commands which depend on the
same module. Follow-up commits will change the internal build system to
continue after a timeout, and reduce the timeout. Perhaps we should
reconsider blocking at all.
This also fixes a use-after-free, when one part of a compilation
validates a PCM and starts using it, and another tries to swap out the
PCM for something new.
The PCMCache is a new type called MemoryBufferCache, which saves memory
buffers based on their filename. Its ownership is shared by the
CompilerInstance and ModuleManager.
- The ModuleManager stores PCMs there that it loads from disk, never
touching the disk if the cache is hot.
- When modules fail to validate, they're removed from the cache.
- When a CompilerInstance is spawned to build a new module, each
already-loaded PCM is assumed to be valid, and is frozen to avoid
the use-after-free.
- Any newly-built module is written directly to the cache to avoid the
round-trip to the filesystem, making lock files unnecessary for
correctness.
Original patch by Manman Ren; most testcases by Adrian Prantl!
llvm-svn: 298278
2017-03-21 01:58:26 +08:00
|
|
|
AST->WriterData.reset(new ASTWriterData(*AST->PCMCache));
|
2014-08-29 07:51:01 +08:00
|
|
|
// Zero out now to ease cleanup during crash recovery.
|
|
|
|
CI = nullptr;
|
|
|
|
Diags = nullptr;
|
2014-05-22 12:46:25 +08:00
|
|
|
|
2011-03-18 10:06:56 +08:00
|
|
|
// Recover resources if we crash before exiting this method.
|
2011-03-22 09:15:24 +08:00
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
|
|
|
|
ASTUnitCleanup(AST.get());
|
2011-03-18 10:06:56 +08:00
|
|
|
|
2016-06-13 04:05:23 +08:00
|
|
|
if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps),
|
2017-05-23 19:37:52 +08:00
|
|
|
PrecompilePreambleAfterNParses,
|
|
|
|
VFS)) {
|
2012-04-11 10:11:16 +08:00
|
|
|
// Some error occurred, if caller wants to examine diagnostics, pass it the
|
|
|
|
// ASTUnit.
|
|
|
|
if (ErrAST) {
|
|
|
|
AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics);
|
|
|
|
ErrAST->swap(AST);
|
|
|
|
}
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2012-04-11 10:11:16 +08:00
|
|
|
}
|
|
|
|
|
2014-03-08 03:33:25 +08:00
|
|
|
return AST.release();
|
2009-12-02 11:23:45 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2015-06-21 02:53:08 +08:00
|
|
|
bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
2017-05-23 19:37:52 +08:00
|
|
|
ArrayRef<RemappedFile> RemappedFiles,
|
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
|
2011-03-22 02:40:17 +08:00
|
|
|
if (!Invocation)
|
2010-07-20 05:46:24 +08:00
|
|
|
return true;
|
2011-10-31 15:19:59 +08:00
|
|
|
|
2017-05-23 19:37:52 +08:00
|
|
|
if (!VFS) {
|
|
|
|
assert(FileMgr && "FileMgr is null on Reparse call");
|
|
|
|
VFS = FileMgr->getVirtualFileSystem();
|
|
|
|
}
|
|
|
|
|
2011-10-31 15:19:59 +08:00
|
|
|
clearFileLevelDecls();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
SimpleTimer ParsingTimer(WantTiming);
|
2010-11-10 04:00:56 +08:00
|
|
|
ParsingTimer.setOutput("Reparsing " + getMainFileName());
|
2010-10-28 23:44:59 +08:00
|
|
|
|
2010-07-31 08:40:00 +08:00
|
|
|
// Remap files.
|
2010-08-20 08:02:33 +08:00
|
|
|
PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
|
2014-07-07 15:47:20 +08:00
|
|
|
for (const auto &RB : PPOpts.RemappedFileBuffers)
|
|
|
|
delete RB.second;
|
|
|
|
|
2010-07-31 08:40:00 +08:00
|
|
|
Invocation->getPreprocessorOpts().clearRemappedFiles();
|
2015-02-07 02:36:04 +08:00
|
|
|
for (const auto &RemappedFile : RemappedFiles) {
|
|
|
|
Invocation->getPreprocessorOpts().addRemappedFile(RemappedFile.first,
|
|
|
|
RemappedFile.second);
|
2011-03-05 09:03:53 +08:00
|
|
|
}
|
2014-02-08 08:38:15 +08:00
|
|
|
|
2010-08-04 13:53:38 +08:00
|
|
|
// If we have a preamble file lying around, or if we might try to
|
|
|
|
// build a precompiled preamble, do so now.
|
2014-08-19 00:23:45 +08:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
|
2017-06-21 18:24:58 +08:00
|
|
|
if (Preamble || PreambleRebuildCounter > 0)
|
2015-06-21 02:53:08 +08:00
|
|
|
OverrideMainBuffer =
|
2017-05-23 19:37:52 +08:00
|
|
|
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
|
|
|
|
|
2015-06-21 02:53:08 +08:00
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
// Clear out the diagnostics state.
|
2015-10-06 22:45:20 +08:00
|
|
|
FileMgr.reset();
|
2011-11-04 04:28:19 +08:00
|
|
|
getDiagnostics().Reset();
|
|
|
|
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
|
2011-11-04 04:57:33 +08:00
|
|
|
if (OverrideMainBuffer)
|
|
|
|
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
|
2011-11-04 04:28:19 +08:00
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// Parse the sources
|
2016-06-13 04:05:23 +08:00
|
|
|
bool Result =
|
2017-05-23 19:37:52 +08:00
|
|
|
Parse(std::move(PCHContainerOps), std::move(OverrideMainBuffer), VFS);
|
2014-08-19 00:23:45 +08:00
|
|
|
|
2018-02-26 23:16:42 +08:00
|
|
|
// If we're caching global code-completion results, and the top-level
|
2011-11-01 05:25:31 +08:00
|
|
|
// declarations have changed, clear out the code-completion cache.
|
|
|
|
if (!Result && ShouldCacheCodeCompletionResults &&
|
|
|
|
CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue)
|
|
|
|
CacheCodeCompletionResults();
|
2011-02-17 02:16:54 +08:00
|
|
|
|
2012-04-11 01:23:48 +08:00
|
|
|
// We now need to clear out the completion info related to this translation
|
|
|
|
// unit; it'll be recreated if necessary.
|
|
|
|
CCTUInfo.reset();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
return Result;
|
2010-07-20 05:46:24 +08:00
|
|
|
}
|
2010-08-05 00:47:14 +08:00
|
|
|
|
2017-05-30 22:25:54 +08:00
|
|
|
void ASTUnit::ResetForParse() {
|
|
|
|
SavedMainFileBuffer.reset();
|
|
|
|
|
|
|
|
SourceMgr.reset();
|
|
|
|
TheSema.reset();
|
|
|
|
Ctx.reset();
|
|
|
|
PP.reset();
|
|
|
|
Reader.reset();
|
|
|
|
|
|
|
|
TopLevelDecls.clear();
|
|
|
|
clearFileLevelDecls();
|
|
|
|
}
|
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// Code completion
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
/// \brief Code completion consumer that combines the cached code-completion
|
|
|
|
/// results from an ASTUnit with the code-completion results provided to it,
|
2018-02-26 23:16:42 +08:00
|
|
|
/// then passes the result on to
|
2010-08-14 06:48:40 +08:00
|
|
|
class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer {
|
2012-08-14 11:13:00 +08:00
|
|
|
uint64_t NormalContexts;
|
2010-08-14 06:48:40 +08:00
|
|
|
ASTUnit &AST;
|
|
|
|
CodeCompleteConsumer &Next;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
public:
|
|
|
|
AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next,
|
2012-07-03 01:35:10 +08:00
|
|
|
const CodeCompleteOptions &CodeCompleteOpts)
|
|
|
|
: CodeCompleteConsumer(CodeCompleteOpts, Next.isOutputBinary()),
|
|
|
|
AST(AST), Next(Next)
|
2018-02-26 23:16:42 +08:00
|
|
|
{
|
2010-08-14 06:48:40 +08:00
|
|
|
// Compute the set of contexts in which we will look when we don't have
|
|
|
|
// any information about the specific context.
|
2018-02-26 23:16:42 +08:00
|
|
|
NormalContexts
|
2012-08-14 11:13:00 +08:00
|
|
|
= (1LL << CodeCompletionContext::CCC_TopLevel)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCInterface)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCImplementation)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCIvarList)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Statement)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Expression)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCMessageReceiver)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_DotMemberAccess)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ArrowMemberAccess)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCPropertyAccess)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ObjCProtocolName)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ParenthesizedExpression)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_Recovery);
|
2010-09-15 07:59:36 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (AST.getASTContext().getLangOpts().CPlusPlus)
|
2012-08-14 11:13:00 +08:00
|
|
|
NormalContexts |= (1LL << CodeCompletionContext::CCC_EnumTag)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_UnionTag)
|
|
|
|
| (1LL << CodeCompletionContext::CCC_ClassOrStructTag);
|
2010-08-14 06:48:40 +08:00
|
|
|
}
|
2014-03-13 14:07:04 +08:00
|
|
|
|
|
|
|
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
|
|
|
|
CodeCompletionResult *Results,
|
|
|
|
unsigned NumResults) override;
|
|
|
|
|
|
|
|
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
|
|
|
|
OverloadCandidate *Candidates,
|
|
|
|
unsigned NumCandidates) override {
|
2010-08-14 06:48:40 +08:00
|
|
|
Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates);
|
|
|
|
}
|
2014-03-13 14:07:04 +08:00
|
|
|
|
|
|
|
CodeCompletionAllocator &getAllocator() override {
|
2011-02-02 03:23:04 +08:00
|
|
|
return Next.getAllocator();
|
|
|
|
}
|
2012-04-11 01:23:48 +08:00
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
CodeCompletionTUInfo &getCodeCompletionTUInfo() override {
|
2012-04-11 01:23:48 +08:00
|
|
|
return Next.getCodeCompletionTUInfo();
|
|
|
|
}
|
2010-08-14 06:48:40 +08:00
|
|
|
};
|
2015-10-07 07:40:43 +08:00
|
|
|
} // anonymous namespace
|
2010-08-17 04:01:48 +08:00
|
|
|
|
2010-08-17 05:18:39 +08:00
|
|
|
/// \brief Helper function that computes which global names are hidden by the
|
|
|
|
/// local code-completion results.
|
2010-11-07 14:11:36 +08:00
|
|
|
static void CalculateHiddenNames(const CodeCompletionContext &Context,
|
|
|
|
CodeCompletionResult *Results,
|
|
|
|
unsigned NumResults,
|
|
|
|
ASTContext &Ctx,
|
|
|
|
llvm::StringSet<llvm::BumpPtrAllocator> &HiddenNames){
|
2010-08-17 05:18:39 +08:00
|
|
|
bool OnlyTagNames = false;
|
|
|
|
switch (Context.getKind()) {
|
2010-09-24 07:01:17 +08:00
|
|
|
case CodeCompletionContext::CCC_Recovery:
|
2010-08-17 05:18:39 +08:00
|
|
|
case CodeCompletionContext::CCC_TopLevel:
|
|
|
|
case CodeCompletionContext::CCC_ObjCInterface:
|
|
|
|
case CodeCompletionContext::CCC_ObjCImplementation:
|
|
|
|
case CodeCompletionContext::CCC_ObjCIvarList:
|
|
|
|
case CodeCompletionContext::CCC_ClassStructUnion:
|
|
|
|
case CodeCompletionContext::CCC_Statement:
|
|
|
|
case CodeCompletionContext::CCC_Expression:
|
|
|
|
case CodeCompletionContext::CCC_ObjCMessageReceiver:
|
2011-07-08 00:03:39 +08:00
|
|
|
case CodeCompletionContext::CCC_DotMemberAccess:
|
|
|
|
case CodeCompletionContext::CCC_ArrowMemberAccess:
|
|
|
|
case CodeCompletionContext::CCC_ObjCPropertyAccess:
|
2010-08-17 05:18:39 +08:00
|
|
|
case CodeCompletionContext::CCC_Namespace:
|
|
|
|
case CodeCompletionContext::CCC_Type:
|
2010-08-24 02:23:48 +08:00
|
|
|
case CodeCompletionContext::CCC_Name:
|
|
|
|
case CodeCompletionContext::CCC_PotentiallyQualifiedName:
|
2010-09-15 07:59:36 +08:00
|
|
|
case CodeCompletionContext::CCC_ParenthesizedExpression:
|
2011-07-30 14:55:39 +08:00
|
|
|
case CodeCompletionContext::CCC_ObjCInterfaceName:
|
2010-08-17 05:18:39 +08:00
|
|
|
break;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 05:18:39 +08:00
|
|
|
case CodeCompletionContext::CCC_EnumTag:
|
|
|
|
case CodeCompletionContext::CCC_UnionTag:
|
|
|
|
case CodeCompletionContext::CCC_ClassOrStructTag:
|
|
|
|
OnlyTagNames = true;
|
|
|
|
break;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 05:18:39 +08:00
|
|
|
case CodeCompletionContext::CCC_ObjCProtocolName:
|
2010-08-25 04:21:13 +08:00
|
|
|
case CodeCompletionContext::CCC_MacroName:
|
|
|
|
case CodeCompletionContext::CCC_MacroNameUse:
|
2010-08-25 06:20:20 +08:00
|
|
|
case CodeCompletionContext::CCC_PreprocessorExpression:
|
2010-08-26 02:41:16 +08:00
|
|
|
case CodeCompletionContext::CCC_PreprocessorDirective:
|
2010-08-26 02:04:30 +08:00
|
|
|
case CodeCompletionContext::CCC_NaturalLanguage:
|
2010-08-26 23:07:07 +08:00
|
|
|
case CodeCompletionContext::CCC_SelectorName:
|
2010-08-28 01:35:51 +08:00
|
|
|
case CodeCompletionContext::CCC_TypeQualifiers:
|
2010-09-24 07:01:17 +08:00
|
|
|
case CodeCompletionContext::CCC_Other:
|
2011-02-19 07:30:37 +08:00
|
|
|
case CodeCompletionContext::CCC_OtherWithMacros:
|
2011-07-08 00:03:39 +08:00
|
|
|
case CodeCompletionContext::CCC_ObjCInstanceMessage:
|
|
|
|
case CodeCompletionContext::CCC_ObjCClassMessage:
|
|
|
|
case CodeCompletionContext::CCC_ObjCCategoryName:
|
2010-08-26 02:41:16 +08:00
|
|
|
// We're looking for nothing, or we're looking for names that cannot
|
|
|
|
// be hidden.
|
2010-08-17 05:18:39 +08:00
|
|
|
return;
|
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-25 14:19:51 +08:00
|
|
|
typedef CodeCompletionResult Result;
|
2010-08-17 05:18:39 +08:00
|
|
|
for (unsigned I = 0; I != NumResults; ++I) {
|
|
|
|
if (Results[I].Kind != Result::RK_Declaration)
|
|
|
|
continue;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 05:18:39 +08:00
|
|
|
unsigned IDNS
|
|
|
|
= Results[I].Declaration->getUnderlyingDecl()->getIdentifierNamespace();
|
|
|
|
|
|
|
|
bool Hiding = false;
|
|
|
|
if (OnlyTagNames)
|
|
|
|
Hiding = (IDNS & Decl::IDNS_Tag);
|
|
|
|
else {
|
2018-02-26 23:16:42 +08:00
|
|
|
unsigned HiddenIDNS = (Decl::IDNS_Type | Decl::IDNS_Member |
|
2010-08-17 07:05:20 +08:00
|
|
|
Decl::IDNS_Namespace | Decl::IDNS_Ordinary |
|
|
|
|
Decl::IDNS_NonMemberOperator);
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Ctx.getLangOpts().CPlusPlus)
|
2010-08-17 05:18:39 +08:00
|
|
|
HiddenIDNS |= Decl::IDNS_Tag;
|
|
|
|
Hiding = (IDNS & HiddenIDNS);
|
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 05:18:39 +08:00
|
|
|
if (!Hiding)
|
|
|
|
continue;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 05:18:39 +08:00
|
|
|
DeclarationName Name = Results[I].Declaration->getDeclName();
|
|
|
|
if (IdentifierInfo *Identifier = Name.getAsIdentifierInfo())
|
|
|
|
HiddenNames.insert(Identifier->getName());
|
|
|
|
else
|
|
|
|
HiddenNames.insert(Name.getAsString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-17 04:01:48 +08:00
|
|
|
void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S,
|
|
|
|
CodeCompletionContext Context,
|
2010-08-25 14:19:51 +08:00
|
|
|
CodeCompletionResult *Results,
|
2018-02-26 23:16:42 +08:00
|
|
|
unsigned NumResults) {
|
2010-08-17 04:01:48 +08:00
|
|
|
// Merge the results we were given with the results we cached.
|
|
|
|
bool AddedResult = false;
|
2012-08-14 11:13:00 +08:00
|
|
|
uint64_t InContexts =
|
|
|
|
Context.getKind() == CodeCompletionContext::CCC_Recovery
|
|
|
|
? NormalContexts : (1LL << Context.getKind());
|
2010-08-17 05:18:39 +08:00
|
|
|
// Contains the set of names that are hidden by "local" completion results.
|
2010-11-07 14:11:36 +08:00
|
|
|
llvm::StringSet<llvm::BumpPtrAllocator> HiddenNames;
|
2010-08-25 14:19:51 +08:00
|
|
|
typedef CodeCompletionResult Result;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Result, 8> AllResults;
|
2018-02-26 23:16:42 +08:00
|
|
|
for (ASTUnit::cached_completion_iterator
|
2010-08-17 05:23:13 +08:00
|
|
|
C = AST.cached_completion_begin(),
|
|
|
|
CEnd = AST.cached_completion_end();
|
2010-08-17 04:01:48 +08:00
|
|
|
C != CEnd; ++C) {
|
2018-02-26 23:16:42 +08:00
|
|
|
// If the context we are in matches any of the contexts we are
|
2010-08-17 04:01:48 +08:00
|
|
|
// interested in, we'll add this result.
|
|
|
|
if ((C->ShowInContexts & InContexts) == 0)
|
|
|
|
continue;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 04:01:48 +08:00
|
|
|
// If we haven't added any results previously, do so now.
|
|
|
|
if (!AddedResult) {
|
2018-02-26 23:16:42 +08:00
|
|
|
CalculateHiddenNames(Context, Results, NumResults, S.Context,
|
2010-08-17 05:18:39 +08:00
|
|
|
HiddenNames);
|
2010-08-17 04:01:48 +08:00
|
|
|
AllResults.insert(AllResults.end(), Results, Results + NumResults);
|
|
|
|
AddedResult = true;
|
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 05:18:39 +08:00
|
|
|
// Determine whether this global completion result is hidden by a local
|
|
|
|
// completion result. If so, skip it.
|
|
|
|
if (C->Kind != CXCursor_MacroDefinition &&
|
|
|
|
HiddenNames.count(C->Completion->getTypedText()))
|
|
|
|
continue;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 04:01:48 +08:00
|
|
|
// Adjust priority based on similar type classes.
|
|
|
|
unsigned Priority = C->Priority;
|
2010-08-25 04:21:13 +08:00
|
|
|
CodeCompletionString *Completion = C->Completion;
|
2010-08-17 04:01:48 +08:00
|
|
|
if (!Context.getPreferredType().isNull()) {
|
|
|
|
if (C->Kind == CXCursor_MacroDefinition) {
|
|
|
|
Priority = getMacroUsagePriority(C->Completion->getTypedText(),
|
2012-03-11 15:00:24 +08:00
|
|
|
S.getLangOpts(),
|
2018-02-26 23:16:42 +08:00
|
|
|
Context.getPreferredType()->isAnyPointerType());
|
2010-08-17 04:01:48 +08:00
|
|
|
} else if (C->Type) {
|
|
|
|
CanQualType Expected
|
2010-08-17 05:23:13 +08:00
|
|
|
= S.Context.getCanonicalType(
|
2010-08-17 04:01:48 +08:00
|
|
|
Context.getPreferredType().getUnqualifiedType());
|
|
|
|
SimplifiedTypeClass ExpectedSTC = getSimplifiedTypeClass(Expected);
|
|
|
|
if (ExpectedSTC == C->TypeClass) {
|
|
|
|
// We know this type is similar; check for an exact match.
|
|
|
|
llvm::StringMap<unsigned> &CachedCompletionTypes
|
2010-08-17 05:23:13 +08:00
|
|
|
= AST.getCachedCompletionTypes();
|
2010-08-17 04:01:48 +08:00
|
|
|
llvm::StringMap<unsigned>::iterator Pos
|
2010-08-17 05:23:13 +08:00
|
|
|
= CachedCompletionTypes.find(QualType(Expected).getAsString());
|
2010-08-17 04:01:48 +08:00
|
|
|
if (Pos != CachedCompletionTypes.end() && Pos->second == C->Type)
|
|
|
|
Priority /= CCF_ExactTypeMatch;
|
|
|
|
else
|
|
|
|
Priority /= CCF_SimilarTypeMatch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-25 04:21:13 +08:00
|
|
|
// Adjust the completion string, if required.
|
|
|
|
if (C->Kind == CXCursor_MacroDefinition &&
|
|
|
|
Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) {
|
|
|
|
// Create a new code-completion string that just contains the
|
|
|
|
// macro name, without its arguments.
|
2012-04-11 01:23:48 +08:00
|
|
|
CodeCompletionBuilder Builder(getAllocator(), getCodeCompletionTUInfo(),
|
|
|
|
CCP_CodePattern, C->Availability);
|
2011-02-02 03:23:04 +08:00
|
|
|
Builder.AddTypedTextChunk(C->Completion->getTypedText());
|
2010-08-26 02:03:13 +08:00
|
|
|
Priority = CCP_CodePattern;
|
2011-02-02 03:23:04 +08:00
|
|
|
Completion = Builder.TakeString();
|
2010-08-25 04:21:13 +08:00
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2012-09-27 08:24:09 +08:00
|
|
|
AllResults.push_back(Result(Completion, Priority, C->Kind,
|
2010-08-24 07:00:57 +08:00
|
|
|
C->Availability));
|
2010-08-17 04:01:48 +08:00
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 04:01:48 +08:00
|
|
|
// If we did not add any cached completion results, just forward the
|
|
|
|
// results we were given to the next consumer.
|
|
|
|
if (!AddedResult) {
|
|
|
|
Next.ProcessCodeCompleteResults(S, Context, Results, NumResults);
|
|
|
|
return;
|
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-17 04:01:48 +08:00
|
|
|
Next.ProcessCodeCompleteResults(S, Context, AllResults.data(),
|
|
|
|
AllResults.size());
|
|
|
|
}
|
|
|
|
|
2015-06-21 02:53:08 +08:00
|
|
|
void ASTUnit::CodeComplete(
|
|
|
|
StringRef File, unsigned Line, unsigned Column,
|
|
|
|
ArrayRef<RemappedFile> RemappedFiles, bool IncludeMacros,
|
|
|
|
bool IncludeCodePatterns, bool IncludeBriefComments,
|
|
|
|
CodeCompleteConsumer &Consumer,
|
|
|
|
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
|
|
|
|
DiagnosticsEngine &Diag, LangOptions &LangOpts, SourceManager &SourceMgr,
|
|
|
|
FileManager &FileMgr, SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
|
|
|
|
SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) {
|
2011-03-22 02:40:17 +08:00
|
|
|
if (!Invocation)
|
2010-08-05 00:47:14 +08:00
|
|
|
return;
|
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
SimpleTimer CompletionTimer(WantTiming);
|
2010-11-10 04:00:56 +08:00
|
|
|
CompletionTimer.setOutput("Code completion @ " + File + ":" +
|
2011-07-23 18:55:15 +08:00
|
|
|
Twine(Line) + ":" + Twine(Column));
|
2010-08-10 04:45:32 +08:00
|
|
|
|
2017-01-07 03:49:01 +08:00
|
|
|
auto CCInvocation = std::make_shared<CompilerInvocation>(*Invocation);
|
2011-03-22 02:40:17 +08:00
|
|
|
|
|
|
|
FrontendOptions &FrontendOpts = CCInvocation->getFrontendOpts();
|
2012-07-03 01:35:10 +08:00
|
|
|
CodeCompleteOptions &CodeCompleteOpts = FrontendOpts.CodeCompleteOpts;
|
2011-03-22 02:40:17 +08:00
|
|
|
PreprocessorOptions &PreprocessorOpts = CCInvocation->getPreprocessorOpts();
|
2010-08-05 17:09:23 +08:00
|
|
|
|
2012-07-03 01:35:10 +08:00
|
|
|
CodeCompleteOpts.IncludeMacros = IncludeMacros &&
|
|
|
|
CachedCompletionResults.empty();
|
|
|
|
CodeCompleteOpts.IncludeCodePatterns = IncludeCodePatterns;
|
|
|
|
CodeCompleteOpts.IncludeGlobals = CachedCompletionResults.empty();
|
|
|
|
CodeCompleteOpts.IncludeBriefComments = IncludeBriefComments;
|
2018-01-12 22:51:47 +08:00
|
|
|
CodeCompleteOpts.LoadExternal = Consumer.loadExternal();
|
2012-07-03 01:35:10 +08:00
|
|
|
|
|
|
|
assert(IncludeBriefComments == this->IncludeBriefCommentsInCodeCompletion);
|
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
FrontendOpts.CodeCompletionAt.FileName = File;
|
|
|
|
FrontendOpts.CodeCompletionAt.Line = Line;
|
|
|
|
FrontendOpts.CodeCompletionAt.Column = Column;
|
|
|
|
|
|
|
|
// Set the language options appropriately.
|
2011-11-18 07:01:24 +08:00
|
|
|
LangOpts = *CCInvocation->getLangOpts();
|
2010-08-05 00:47:14 +08:00
|
|
|
|
2014-11-01 00:44:32 +08:00
|
|
|
// Spell-checking and warnings are wasteful during code-completion.
|
|
|
|
LangOpts.SpellChecking = false;
|
|
|
|
CCInvocation->getDiagnosticOpts().IgnoreWarnings = true;
|
|
|
|
|
2015-06-21 02:53:08 +08:00
|
|
|
std::unique_ptr<CompilerInstance> Clang(
|
|
|
|
new CompilerInstance(PCHContainerOps));
|
2011-03-22 02:40:07 +08:00
|
|
|
|
|
|
|
// Recover resources if we crash before exiting this method.
|
2011-03-22 09:15:24 +08:00
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
|
|
|
|
CICleanup(Clang.get());
|
2011-03-22 02:40:07 +08:00
|
|
|
|
2017-01-07 03:49:01 +08:00
|
|
|
auto &Inv = *CCInvocation;
|
|
|
|
Clang->setInvocation(std::move(CCInvocation));
|
2012-11-10 03:40:39 +08:00
|
|
|
OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Set up diagnostics, capturing any diagnostics produced.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setDiagnostics(&Diag);
|
2018-02-26 23:16:42 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(true,
|
|
|
|
Clang->getDiagnostics(),
|
2017-06-21 18:24:58 +08:00
|
|
|
&StoredDiagnostics, nullptr);
|
2017-01-07 03:49:01 +08:00
|
|
|
ProcessWarningOptions(Diag, Inv.getDiagnosticOpts());
|
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Create the target instance.
|
2014-07-06 13:26:44 +08:00
|
|
|
Clang->setTarget(TargetInfo::CreateTargetInfo(
|
2016-04-09 00:52:00 +08:00
|
|
|
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
|
2011-03-22 02:40:07 +08:00
|
|
|
if (!Clang->hasTarget()) {
|
2014-05-22 12:46:25 +08:00
|
|
|
Clang->setInvocation(nullptr);
|
2010-08-19 06:29:43 +08:00
|
|
|
return;
|
2010-08-05 00:47:14 +08:00
|
|
|
}
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Inform the target of the language options.
|
|
|
|
//
|
|
|
|
// FIXME: We shouldn't need to do this, the target should be immutable once
|
|
|
|
// created. This complexity should be lifted elsewhere.
|
2014-07-06 13:14:24 +08:00
|
|
|
Clang->getTarget().adjust(Clang->getLangOpts());
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-03-22 02:40:07 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
|
2010-08-05 00:47:14 +08:00
|
|
|
"Invocation must have exactly one source file!");
|
2017-04-27 02:57:40 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() ==
|
|
|
|
InputKind::Source &&
|
2010-08-05 00:47:14 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2017-04-27 02:57:40 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
|
|
|
|
InputKind::LLVM_IR &&
|
2010-08-05 00:47:14 +08:00
|
|
|
"IR inputs not support here!");
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Use the source and file managers that we were given.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setFileManager(&FileMgr);
|
|
|
|
Clang->setSourceManager(&SourceMgr);
|
2010-08-05 00:47:14 +08:00
|
|
|
|
|
|
|
// Remap files.
|
|
|
|
PreprocessorOpts.clearRemappedFiles();
|
2010-08-05 01:07:00 +08:00
|
|
|
PreprocessorOpts.RetainRemappedFileBuffers = true;
|
2015-02-07 02:36:04 +08:00
|
|
|
for (const auto &RemappedFile : RemappedFiles) {
|
|
|
|
PreprocessorOpts.addRemappedFile(RemappedFile.first, RemappedFile.second);
|
|
|
|
OwnedBuffers.push_back(RemappedFile.second);
|
2010-08-20 08:59:43 +08:00
|
|
|
}
|
2014-02-08 08:38:15 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
// Use the code completion consumer we were given, but adding any cached
|
|
|
|
// code-completion results.
|
2010-11-30 00:13:56 +08:00
|
|
|
AugmentedCodeCompleteConsumer *AugmentedConsumer
|
2012-07-03 01:35:10 +08:00
|
|
|
= new AugmentedCodeCompleteConsumer(*this, Consumer, CodeCompleteOpts);
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setCodeCompletionConsumer(AugmentedConsumer);
|
2010-08-05 00:47:14 +08:00
|
|
|
|
2010-08-10 04:45:32 +08:00
|
|
|
// If we have a precompiled preamble, try to use it. We only allow
|
|
|
|
// the use of the precompiled preamble if we're if the completion
|
|
|
|
// point is within the main file, after the end of the precompiled
|
|
|
|
// preamble.
|
2014-08-19 02:47:08 +08:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
|
2017-06-21 18:24:58 +08:00
|
|
|
if (Preamble) {
|
2013-06-19 03:40:07 +08:00
|
|
|
std::string CompleteFilePath(File);
|
|
|
|
|
2017-05-23 19:37:52 +08:00
|
|
|
auto VFS = FileMgr.getVirtualFileSystem();
|
|
|
|
auto CompleteFileStatus = VFS->status(CompleteFilePath);
|
|
|
|
if (CompleteFileStatus) {
|
|
|
|
llvm::sys::fs::UniqueID CompleteFileID = CompleteFileStatus->getUniqueID();
|
|
|
|
|
2013-06-19 03:40:07 +08:00
|
|
|
std::string MainPath(OriginalSourceFile);
|
2017-05-23 19:37:52 +08:00
|
|
|
auto MainStatus = VFS->status(MainPath);
|
|
|
|
if (MainStatus) {
|
|
|
|
llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID();
|
2013-06-19 03:40:07 +08:00
|
|
|
if (CompleteFileID == MainID && Line > 1)
|
2014-08-19 02:47:08 +08:00
|
|
|
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
|
2017-05-23 19:37:52 +08:00
|
|
|
PCHContainerOps, Inv, VFS, false, Line - 1);
|
2013-06-19 03:40:07 +08:00
|
|
|
}
|
|
|
|
}
|
2010-08-10 04:45:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the main file has been overridden due to the use of a preamble,
|
|
|
|
// make that override happen and introduce the preamble.
|
|
|
|
if (OverrideMainBuffer) {
|
2017-11-17 00:25:01 +08:00
|
|
|
assert(Preamble &&
|
|
|
|
"No preamble was built, but OverrideMainBuffer is not null");
|
|
|
|
|
|
|
|
auto VFS = FileMgr.getVirtualFileSystem();
|
|
|
|
Preamble->AddImplicitPreamble(Clang->getInvocation(), VFS,
|
|
|
|
OverrideMainBuffer.get());
|
|
|
|
// FIXME: there is no way to update VFS if it was changed by
|
|
|
|
// AddImplicitPreamble as FileMgr is accepted as a parameter by this method.
|
|
|
|
// We use on-disk preambles instead and rely on FileMgr's VFS to ensure the
|
|
|
|
// PCH files are always readable.
|
2014-08-19 02:47:08 +08:00
|
|
|
OwnedBuffers.push_back(OverrideMainBuffer.release());
|
2010-08-20 08:02:33 +08:00
|
|
|
} else {
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
|
2010-08-10 04:45:32 +08:00
|
|
|
}
|
|
|
|
|
2012-11-03 06:18:44 +08:00
|
|
|
// Disable the preprocessing record if modules are not enabled.
|
|
|
|
if (!Clang->getLangOpts().Modules)
|
|
|
|
PreprocessorOpts.DetailedRecord = false;
|
2014-03-08 04:03:18 +08:00
|
|
|
|
|
|
|
std::unique_ptr<SyntaxOnlyAction> Act;
|
2010-08-05 00:47:14 +08:00
|
|
|
Act.reset(new SyntaxOnlyAction);
|
2012-01-21 00:28:04 +08:00
|
|
|
if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
|
2010-08-05 00:47:14 +08:00
|
|
|
Act->Execute();
|
|
|
|
Act->EndSourceFile();
|
|
|
|
}
|
|
|
|
}
|
2010-08-13 13:36:37 +08:00
|
|
|
|
2012-09-27 00:39:46 +08:00
|
|
|
bool ASTUnit::Save(StringRef File) {
|
2013-05-24 13:44:08 +08:00
|
|
|
if (HadModuleLoaderFatalFailure)
|
|
|
|
return true;
|
|
|
|
|
2011-07-22 02:44:49 +08:00
|
|
|
// Write to a temporary file and later rename it to the actual file, to avoid
|
|
|
|
// possible race conditions.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> TempPath;
|
2011-07-28 08:45:10 +08:00
|
|
|
TempPath = File;
|
|
|
|
TempPath += "-%%%%%%%%";
|
|
|
|
int fd;
|
2015-03-18 18:17:07 +08:00
|
|
|
if (llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath))
|
2012-09-27 00:39:46 +08:00
|
|
|
return true;
|
2011-07-22 02:44:49 +08:00
|
|
|
|
2018-02-26 23:16:42 +08:00
|
|
|
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
|
2010-08-13 13:36:37 +08:00
|
|
|
// unconditionally create a stat cache when we parse the file?
|
2011-07-28 08:45:10 +08:00
|
|
|
llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true);
|
2011-03-10 01:21:42 +08:00
|
|
|
|
|
|
|
serialize(Out);
|
|
|
|
Out.close();
|
2012-03-13 10:17:06 +08:00
|
|
|
if (Out.has_error()) {
|
|
|
|
Out.clear_error();
|
2012-09-27 00:39:46 +08:00
|
|
|
return true;
|
2012-03-13 10:17:06 +08:00
|
|
|
}
|
2011-07-22 02:44:49 +08:00
|
|
|
|
2015-03-18 18:17:07 +08:00
|
|
|
if (llvm::sys::fs::rename(TempPath, File)) {
|
|
|
|
llvm::sys::fs::remove(TempPath);
|
2012-09-27 00:39:46 +08:00
|
|
|
return true;
|
2011-07-22 02:44:49 +08:00
|
|
|
}
|
|
|
|
|
2012-09-27 00:39:46 +08:00
|
|
|
return false;
|
2011-03-10 01:21:42 +08:00
|
|
|
}
|
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
static bool serializeUnit(ASTWriter &Writer,
|
|
|
|
SmallVectorImpl<char> &Buffer,
|
|
|
|
Sema &S,
|
|
|
|
bool hasErrors,
|
|
|
|
raw_ostream &OS) {
|
2014-05-22 12:46:25 +08:00
|
|
|
Writer.WriteAST(S, std::string(), nullptr, "", hasErrors);
|
2012-10-12 00:05:00 +08:00
|
|
|
|
|
|
|
// Write the generated bitstream to "Out".
|
|
|
|
if (!Buffer.empty())
|
|
|
|
OS.write(Buffer.data(), Buffer.size());
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
bool ASTUnit::serialize(raw_ostream &OS) {
|
2016-07-14 04:35:26 +08:00
|
|
|
// For serialization we are lenient if the errors were only warn-as-error kind.
|
|
|
|
bool hasErrors = getDiagnostics().hasUncompilableErrorOccurred();
|
2011-03-10 01:21:42 +08:00
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
if (WriterData)
|
|
|
|
return serializeUnit(WriterData->Writer, WriterData->Buffer,
|
|
|
|
getSema(), hasErrors, OS);
|
|
|
|
|
2012-03-01 04:31:23 +08:00
|
|
|
SmallString<128> Buffer;
|
2010-08-13 13:36:37 +08:00
|
|
|
llvm::BitstreamWriter Stream(Buffer);
|
Reapply "Modules: Cache PCMs in memory and avoid a use-after-free"
This reverts commit r298185, effectively reapplying r298165, after fixing the
new unit tests (PR32338). The memory buffer generator doesn't null-terminate
the MemoryBuffer it creates; this version of the commit informs getMemBuffer
about that to avoid the assert.
Original commit message follows:
----
Clang's internal build system for implicit modules uses lock files to
ensure that after a process writes a PCM it will read the same one back
in (without contention from other -cc1 commands). Since PCMs are read
from disk repeatedly while invalidating, building, and importing, the
lock is not released quickly. Furthermore, the LockFileManager is not
robust in every environment. Other -cc1 commands can stall until
timeout (after about eight minutes).
This commit changes the lock file from being necessary for correctness
to a (possibly dubious) performance hack. The remaining benefit is to
reduce duplicate work in competing -cc1 commands which depend on the
same module. Follow-up commits will change the internal build system to
continue after a timeout, and reduce the timeout. Perhaps we should
reconsider blocking at all.
This also fixes a use-after-free, when one part of a compilation
validates a PCM and starts using it, and another tries to swap out the
PCM for something new.
The PCMCache is a new type called MemoryBufferCache, which saves memory
buffers based on their filename. Its ownership is shared by the
CompilerInstance and ModuleManager.
- The ModuleManager stores PCMs there that it loads from disk, never
touching the disk if the cache is hot.
- When modules fail to validate, they're removed from the cache.
- When a CompilerInstance is spawned to build a new module, each
already-loaded PCM is assumed to be valid, and is frozen to avoid
the use-after-free.
- Any newly-built module is written directly to the cache to avoid the
round-trip to the filesystem, making lock files unnecessary for
correctness.
Original patch by Manman Ren; most testcases by Adrian Prantl!
llvm-svn: 298278
2017-03-21 01:58:26 +08:00
|
|
|
MemoryBufferCache PCMCache;
|
|
|
|
ASTWriter Writer(Stream, Buffer, PCMCache, {});
|
2012-10-12 00:05:00 +08:00
|
|
|
return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS);
|
2010-08-13 13:36:37 +08:00
|
|
|
}
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
|
|
|
|
typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap;
|
|
|
|
|
|
|
|
void ASTUnit::TranslateStoredDiagnostics(
|
2014-02-28 15:11:01 +08:00
|
|
|
FileManager &FileMgr,
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
SourceManager &SrcMgr,
|
2014-02-28 15:11:01 +08:00
|
|
|
const SmallVectorImpl<StandaloneDiagnostic> &Diags,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<StoredDiagnostic> &Out) {
|
2014-02-28 15:11:01 +08:00
|
|
|
// Map the standalone diagnostic into the new source manager. We also need to
|
|
|
|
// remap all the locations to the new view. This includes the diag location,
|
|
|
|
// any associated source ranges, and the source ranges of associated fix-its.
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
// FIXME: There should be a cleaner way to do this.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<StoredDiagnostic, 4> Result;
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
Result.reserve(Diags.size());
|
2017-06-09 16:29:58 +08:00
|
|
|
|
2015-02-07 02:36:04 +08:00
|
|
|
for (const StandaloneDiagnostic &SD : Diags) {
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
// Rebuild the StoredDiagnostic.
|
2014-02-28 15:11:01 +08:00
|
|
|
if (SD.Filename.empty())
|
|
|
|
continue;
|
|
|
|
const FileEntry *FE = FileMgr.getFile(SD.Filename);
|
|
|
|
if (!FE)
|
|
|
|
continue;
|
2017-06-09 16:29:58 +08:00
|
|
|
SourceLocation FileLoc;
|
|
|
|
auto ItFileID = PreambleSrcLocCache.find(SD.Filename);
|
|
|
|
if (ItFileID == PreambleSrcLocCache.end()) {
|
|
|
|
FileID FID = SrcMgr.translateFile(FE);
|
|
|
|
FileLoc = SrcMgr.getLocForStartOfFile(FID);
|
|
|
|
PreambleSrcLocCache[SD.Filename] = FileLoc;
|
|
|
|
} else {
|
|
|
|
FileLoc = ItFileID->getValue();
|
Cache FileID when translating diagnostics in PCH files
Modules/preambles/PCH files can contain diagnostics, which, when used,
are added to the current ASTUnit. For that to work, they are translated
to use the current FileManager's FileIDs. When the entry is not the
main file, all local source locations will be checked by a linear
search. Now this is a problem, when there are lots of diagnostics (say,
25000) and lots of local source locations (say, 440000), and end up
taking seconds when using such a preamble.
The fix is to cache the last FileID, because many subsequent diagnostics
refer to the same file. This reduces the time spent in
ASTUnit::TranslateStoredDiagnostics from seconds to a few milliseconds
for files with many slocs/diagnostics.
This fixes PR31353.
Differential Revision: https://reviews.llvm.org/D29755
llvm-svn: 295301
2017-02-16 17:49:30 +08:00
|
|
|
}
|
2017-06-09 16:29:58 +08:00
|
|
|
|
2014-02-28 15:11:01 +08:00
|
|
|
if (FileLoc.isInvalid())
|
|
|
|
continue;
|
|
|
|
SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset);
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
FullSourceLoc Loc(L, SrcMgr);
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<CharSourceRange, 4> Ranges;
|
2014-02-28 15:11:01 +08:00
|
|
|
Ranges.reserve(SD.Ranges.size());
|
2015-02-07 02:36:04 +08:00
|
|
|
for (const auto &Range : SD.Ranges) {
|
|
|
|
SourceLocation BL = FileLoc.getLocWithOffset(Range.first);
|
|
|
|
SourceLocation EL = FileLoc.getLocWithOffset(Range.second);
|
2014-02-28 15:11:01 +08:00
|
|
|
Ranges.push_back(CharSourceRange::getCharRange(BL, EL));
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<FixItHint, 2> FixIts;
|
2014-02-28 15:11:01 +08:00
|
|
|
FixIts.reserve(SD.FixIts.size());
|
2015-02-07 02:36:04 +08:00
|
|
|
for (const StandaloneFixIt &FixIt : SD.FixIts) {
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
FixIts.push_back(FixItHint());
|
|
|
|
FixItHint &FH = FixIts.back();
|
2015-02-07 02:36:04 +08:00
|
|
|
FH.CodeToInsert = FixIt.CodeToInsert;
|
|
|
|
SourceLocation BL = FileLoc.getLocWithOffset(FixIt.RemoveRange.first);
|
|
|
|
SourceLocation EL = FileLoc.getLocWithOffset(FixIt.RemoveRange.second);
|
2014-02-28 15:11:01 +08:00
|
|
|
FH.RemoveRange = CharSourceRange::getCharRange(BL, EL);
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
}
|
|
|
|
|
2018-02-26 23:16:42 +08:00
|
|
|
Result.push_back(StoredDiagnostic(SD.Level, SD.ID,
|
2014-02-28 15:11:01 +08:00
|
|
|
SD.Message, Loc, Ranges, FixIts));
|
Revamp the SourceManager to separate the representation of parsed
source locations from source locations loaded from an AST/PCH file.
Previously, loading an AST/PCH file involved carefully pre-allocating
space at the beginning of the source manager for the source locations
and FileIDs that correspond to the prefix, and then appending the
source locations/FileIDs used for parsing the remaining translation
unit. This design forced us into loading PCH files early, as a prefix,
whic has become a rather significant limitation.
This patch splits the SourceManager space into two parts: for source
location "addresses", the lower values (growing upward) are used to
describe parsed code, while upper values (growing downward) are used
for source locations loaded from AST/PCH files. Similarly, positive
FileIDs are used to describe parsed code while negative FileIDs are
used to file/macro locations loaded from AST/PCH files. As a result,
we can load PCH/AST files even during parsing, making various
improvemnts in the future possible, e.g., teaching #include <foo.h> to
look for and load <foo.h.gch> if it happens to be already available.
This patch was originally written by Sebastian Redl, then brought
forward to the modern age by Jonathan Turner, and finally
polished/finished by me to be committed.
llvm-svn: 135484
2011-07-20 00:10:42 +08:00
|
|
|
}
|
|
|
|
Result.swap(Out);
|
|
|
|
}
|
2011-09-20 04:40:35 +08:00
|
|
|
|
2011-10-31 15:19:59 +08:00
|
|
|
void ASTUnit::addFileLevelDecl(Decl *D) {
|
|
|
|
assert(D);
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-11-08 02:53:57 +08:00
|
|
|
// We only care about local declarations.
|
|
|
|
if (D->isFromASTFile())
|
|
|
|
return;
|
2011-10-31 15:19:59 +08:00
|
|
|
|
|
|
|
SourceManager &SM = *SourceMgr;
|
|
|
|
SourceLocation Loc = D->getLocation();
|
|
|
|
if (Loc.isInvalid() || !SM.isLocalSourceLocation(Loc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We only keep track of the file-level declarations of each file.
|
|
|
|
if (!D->getLexicalDeclContext()->isFileContext())
|
|
|
|
return;
|
|
|
|
|
|
|
|
SourceLocation FileLoc = SM.getFileLoc(Loc);
|
|
|
|
assert(SM.isLocalSourceLocation(FileLoc));
|
|
|
|
FileID FID;
|
|
|
|
unsigned Offset;
|
2014-03-02 21:01:17 +08:00
|
|
|
std::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
|
2011-10-31 15:19:59 +08:00
|
|
|
if (FID.isInvalid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
LocDeclsTy *&Decls = FileDecls[FID];
|
|
|
|
if (!Decls)
|
|
|
|
Decls = new LocDeclsTy();
|
|
|
|
|
|
|
|
std::pair<unsigned, Decl *> LocDecl(Offset, D);
|
|
|
|
|
|
|
|
if (Decls->empty() || Decls->back().first <= Offset) {
|
|
|
|
Decls->push_back(LocDecl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:22:59 +08:00
|
|
|
LocDeclsTy::iterator I = std::upper_bound(Decls->begin(), Decls->end(),
|
|
|
|
LocDecl, llvm::less_first());
|
2011-10-31 15:19:59 +08:00
|
|
|
|
|
|
|
Decls->insert(I, LocDecl);
|
|
|
|
}
|
|
|
|
|
2011-11-03 10:20:32 +08:00
|
|
|
void ASTUnit::findFileRegionDecls(FileID File, unsigned Offset, unsigned Length,
|
|
|
|
SmallVectorImpl<Decl *> &Decls) {
|
|
|
|
if (File.isInvalid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (SourceMgr->isLoadedFileID(File)) {
|
|
|
|
assert(Ctx->getExternalSource() && "No external source!");
|
|
|
|
return Ctx->getExternalSource()->FindFileRegionDecls(File, Offset, Length,
|
|
|
|
Decls);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileDeclsTy::iterator I = FileDecls.find(File);
|
|
|
|
if (I == FileDecls.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
LocDeclsTy &LocDecls = *I->second;
|
|
|
|
if (LocDecls.empty())
|
|
|
|
return;
|
|
|
|
|
2013-08-24 21:12:34 +08:00
|
|
|
LocDeclsTy::iterator BeginIt =
|
|
|
|
std::lower_bound(LocDecls.begin(), LocDecls.end(),
|
2014-05-22 12:46:25 +08:00
|
|
|
std::make_pair(Offset, (Decl *)nullptr),
|
|
|
|
llvm::less_first());
|
2011-11-03 10:20:32 +08:00
|
|
|
if (BeginIt != LocDecls.begin())
|
|
|
|
--BeginIt;
|
|
|
|
|
2011-11-24 04:27:36 +08:00
|
|
|
// If we are pointing at a top-level decl inside an objc container, we need
|
|
|
|
// to backtrack until we find it otherwise we will fail to report that the
|
|
|
|
// region overlaps with an objc container.
|
|
|
|
while (BeginIt != LocDecls.begin() &&
|
|
|
|
BeginIt->second->isTopLevelDeclInObjCContainer())
|
|
|
|
--BeginIt;
|
|
|
|
|
2013-08-24 21:12:34 +08:00
|
|
|
LocDeclsTy::iterator EndIt = std::upper_bound(
|
|
|
|
LocDecls.begin(), LocDecls.end(),
|
2014-05-22 12:46:25 +08:00
|
|
|
std::make_pair(Offset + Length, (Decl *)nullptr), llvm::less_first());
|
2011-11-03 10:20:32 +08:00
|
|
|
if (EndIt != LocDecls.end())
|
|
|
|
++EndIt;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-11-03 10:20:32 +08:00
|
|
|
for (LocDeclsTy::iterator DIt = BeginIt; DIt != EndIt; ++DIt)
|
|
|
|
Decls.push_back(DIt->second);
|
|
|
|
}
|
|
|
|
|
2011-09-20 04:40:35 +08:00
|
|
|
SourceLocation ASTUnit::getLocation(const FileEntry *File,
|
|
|
|
unsigned Line, unsigned Col) const {
|
|
|
|
const SourceManager &SM = getSourceManager();
|
2011-09-26 16:01:41 +08:00
|
|
|
SourceLocation Loc = SM.translateFileLineCol(File, Line, Col);
|
2011-09-20 04:40:35 +08:00
|
|
|
return SM.getMacroArgExpandedLocation(Loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation ASTUnit::getLocation(const FileEntry *File,
|
|
|
|
unsigned Offset) const {
|
|
|
|
const SourceManager &SM = getSourceManager();
|
2011-09-26 16:01:41 +08:00
|
|
|
SourceLocation FileLoc = SM.translateFileLineCol(File, 1, 1);
|
2011-09-20 04:40:35 +08:00
|
|
|
return SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset));
|
|
|
|
}
|
|
|
|
|
2011-09-26 16:01:41 +08:00
|
|
|
/// \brief If \arg Loc is a loaded location from the preamble, returns
|
|
|
|
/// the corresponding local location of the main file, otherwise it returns
|
|
|
|
/// \arg Loc.
|
2017-07-26 03:53:27 +08:00
|
|
|
SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) const {
|
2011-09-26 16:01:41 +08:00
|
|
|
FileID PreambleID;
|
|
|
|
if (SourceMgr)
|
|
|
|
PreambleID = SourceMgr->getPreambleFileID();
|
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
|
2011-09-26 16:01:41 +08:00
|
|
|
return Loc;
|
|
|
|
|
|
|
|
unsigned Offs;
|
2017-06-21 18:24:58 +08:00
|
|
|
if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble->getBounds().Size) {
|
2011-09-26 16:01:41 +08:00
|
|
|
SourceLocation FileLoc
|
|
|
|
= SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID());
|
|
|
|
return FileLoc.getLocWithOffset(Offs);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Loc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief If \arg Loc is a local location of the main file but inside the
|
|
|
|
/// preamble chunk, returns the corresponding loaded location from the
|
|
|
|
/// preamble, otherwise it returns \arg Loc.
|
2017-07-26 03:53:27 +08:00
|
|
|
SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) const {
|
2011-09-26 16:01:41 +08:00
|
|
|
FileID PreambleID;
|
|
|
|
if (SourceMgr)
|
|
|
|
PreambleID = SourceMgr->getPreambleFileID();
|
|
|
|
|
2017-06-21 18:24:58 +08:00
|
|
|
if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
|
2011-09-26 16:01:41 +08:00
|
|
|
return Loc;
|
|
|
|
|
|
|
|
unsigned Offs;
|
|
|
|
if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) &&
|
2017-06-21 18:24:58 +08:00
|
|
|
Offs < Preamble->getBounds().Size) {
|
2011-09-26 16:01:41 +08:00
|
|
|
SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID);
|
|
|
|
return FileLoc.getLocWithOffset(Offs);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Loc;
|
|
|
|
}
|
|
|
|
|
2017-07-26 03:53:27 +08:00
|
|
|
bool ASTUnit::isInPreambleFileID(SourceLocation Loc) const {
|
2011-10-25 08:29:50 +08:00
|
|
|
FileID FID;
|
|
|
|
if (SourceMgr)
|
|
|
|
FID = SourceMgr->getPreambleFileID();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-10-25 08:29:50 +08:00
|
|
|
if (Loc.isInvalid() || FID.isInvalid())
|
|
|
|
return false;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-10-25 08:29:50 +08:00
|
|
|
return SourceMgr->isInFileID(Loc, FID);
|
|
|
|
}
|
|
|
|
|
2017-07-26 03:53:27 +08:00
|
|
|
bool ASTUnit::isInMainFileID(SourceLocation Loc) const {
|
2011-10-25 08:29:50 +08:00
|
|
|
FileID FID;
|
|
|
|
if (SourceMgr)
|
|
|
|
FID = SourceMgr->getMainFileID();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-10-25 08:29:50 +08:00
|
|
|
if (Loc.isInvalid() || FID.isInvalid())
|
|
|
|
return false;
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-10-25 08:29:50 +08:00
|
|
|
return SourceMgr->isInFileID(Loc, FID);
|
|
|
|
}
|
|
|
|
|
2017-07-26 03:53:27 +08:00
|
|
|
SourceLocation ASTUnit::getEndOfPreambleFileID() const {
|
2011-10-25 08:29:50 +08:00
|
|
|
FileID FID;
|
|
|
|
if (SourceMgr)
|
|
|
|
FID = SourceMgr->getPreambleFileID();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-10-25 08:29:50 +08:00
|
|
|
if (FID.isInvalid())
|
|
|
|
return SourceLocation();
|
|
|
|
|
|
|
|
return SourceMgr->getLocForEndOfFile(FID);
|
|
|
|
}
|
|
|
|
|
2017-07-26 03:53:27 +08:00
|
|
|
SourceLocation ASTUnit::getStartOfMainFileID() const {
|
2011-10-25 08:29:50 +08:00
|
|
|
FileID FID;
|
|
|
|
if (SourceMgr)
|
|
|
|
FID = SourceMgr->getMainFileID();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-10-25 08:29:50 +08:00
|
|
|
if (FID.isInvalid())
|
|
|
|
return SourceLocation();
|
2018-02-26 23:16:42 +08:00
|
|
|
|
2011-10-25 08:29:50 +08:00
|
|
|
return SourceMgr->getLocForStartOfFile(FID);
|
|
|
|
}
|
|
|
|
|
2015-02-07 01:25:10 +08:00
|
|
|
llvm::iterator_range<PreprocessingRecord::iterator>
|
2012-10-03 00:10:51 +08:00
|
|
|
ASTUnit::getLocalPreprocessingEntities() const {
|
|
|
|
if (isMainFileAST()) {
|
|
|
|
serialization::ModuleFile &
|
|
|
|
Mod = Reader->getModuleManager().getPrimaryModule();
|
|
|
|
return Reader->getModulePreprocessedEntities(Mod);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
|
2015-02-07 01:25:10 +08:00
|
|
|
return llvm::make_range(PPRec->local_begin(), PPRec->local_end());
|
2012-10-03 00:10:51 +08:00
|
|
|
|
2015-02-07 01:25:10 +08:00
|
|
|
return llvm::make_range(PreprocessingRecord::iterator(),
|
|
|
|
PreprocessingRecord::iterator());
|
2012-10-03 00:10:51 +08:00
|
|
|
}
|
|
|
|
|
2012-10-03 09:58:28 +08:00
|
|
|
bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) {
|
2012-10-03 05:09:13 +08:00
|
|
|
if (isMainFileAST()) {
|
|
|
|
serialization::ModuleFile &
|
|
|
|
Mod = Reader->getModuleManager().getPrimaryModule();
|
2015-02-07 01:25:10 +08:00
|
|
|
for (const Decl *D : Reader->getModuleFileLevelDecls(Mod)) {
|
|
|
|
if (!Fn(context, D))
|
2012-10-03 05:09:13 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ASTUnit::top_level_iterator TL = top_level_begin(),
|
|
|
|
TLEnd = top_level_end();
|
|
|
|
TL != TLEnd; ++TL) {
|
|
|
|
if (!Fn(context, *TL))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-10-04 05:05:51 +08:00
|
|
|
const FileEntry *ASTUnit::getPCHFile() {
|
|
|
|
if (!Reader)
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2012-10-04 05:05:51 +08:00
|
|
|
|
2015-07-25 20:14:04 +08:00
|
|
|
serialization::ModuleFile *Mod = nullptr;
|
|
|
|
Reader->getModuleManager().visit([&Mod](serialization::ModuleFile &M) {
|
|
|
|
switch (M.Kind) {
|
|
|
|
case serialization::MK_ImplicitModule:
|
|
|
|
case serialization::MK_ExplicitModule:
|
2016-08-19 01:42:15 +08:00
|
|
|
case serialization::MK_PrebuiltModule:
|
2015-07-25 20:14:04 +08:00
|
|
|
return true; // skip dependencies.
|
|
|
|
case serialization::MK_PCH:
|
|
|
|
Mod = &M;
|
|
|
|
return true; // found it.
|
|
|
|
case serialization::MK_Preamble:
|
|
|
|
return false; // look in dependencies.
|
|
|
|
case serialization::MK_MainFile:
|
|
|
|
return false; // look in dependencies.
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
if (Mod)
|
|
|
|
return Mod->File;
|
2012-10-04 05:05:51 +08:00
|
|
|
|
2014-05-22 12:46:25 +08:00
|
|
|
return nullptr;
|
2012-10-04 05:05:51 +08:00
|
|
|
}
|
|
|
|
|
2017-07-26 03:53:27 +08:00
|
|
|
bool ASTUnit::isModuleFile() const {
|
2017-06-06 02:10:11 +08:00
|
|
|
return isMainFileAST() && getLangOpts().isCompilingModule();
|
|
|
|
}
|
|
|
|
|
|
|
|
InputKind ASTUnit::getInputKind() const {
|
|
|
|
auto &LangOpts = getLangOpts();
|
|
|
|
|
|
|
|
InputKind::Language Lang;
|
|
|
|
if (LangOpts.OpenCL)
|
|
|
|
Lang = InputKind::OpenCL;
|
|
|
|
else if (LangOpts.CUDA)
|
|
|
|
Lang = InputKind::CUDA;
|
|
|
|
else if (LangOpts.RenderScript)
|
|
|
|
Lang = InputKind::RenderScript;
|
|
|
|
else if (LangOpts.CPlusPlus)
|
|
|
|
Lang = LangOpts.ObjC1 ? InputKind::ObjCXX : InputKind::CXX;
|
|
|
|
else
|
|
|
|
Lang = LangOpts.ObjC1 ? InputKind::ObjC : InputKind::C;
|
|
|
|
|
|
|
|
InputKind::Format Fmt = InputKind::Source;
|
|
|
|
if (LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap)
|
|
|
|
Fmt = InputKind::ModuleMap;
|
|
|
|
|
|
|
|
// We don't know if input was preprocessed. Assume not.
|
|
|
|
bool PP = false;
|
|
|
|
|
|
|
|
return InputKind(Lang, Fmt, PP);
|
2012-10-10 10:12:47 +08:00
|
|
|
}
|
|
|
|
|
2011-10-11 05:57:12 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
ASTUnit::ConcurrencyState::ConcurrencyState() {
|
|
|
|
Mutex = new llvm::sys::MutexImpl(/*recursive=*/true);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTUnit::ConcurrencyState::~ConcurrencyState() {
|
|
|
|
delete static_cast<llvm::sys::MutexImpl *>(Mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::ConcurrencyState::start() {
|
|
|
|
bool acquired = static_cast<llvm::sys::MutexImpl *>(Mutex)->tryacquire();
|
|
|
|
assert(acquired && "Concurrent access to ASTUnit!");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::ConcurrencyState::finish() {
|
|
|
|
static_cast<llvm::sys::MutexImpl *>(Mutex)->release();
|
|
|
|
}
|
|
|
|
|
|
|
|
#else // NDEBUG
|
|
|
|
|
2015-10-07 07:40:43 +08:00
|
|
|
ASTUnit::ConcurrencyState::ConcurrencyState() { Mutex = nullptr; }
|
2015-10-20 21:23:58 +08:00
|
|
|
ASTUnit::ConcurrencyState::~ConcurrencyState() {}
|
2011-10-11 05:57:12 +08:00
|
|
|
void ASTUnit::ConcurrencyState::start() {}
|
|
|
|
void ASTUnit::ConcurrencyState::finish() {}
|
|
|
|
|
2015-10-07 07:40:43 +08:00
|
|
|
#endif // NDEBUG
|