2009-06-20 16:27:14 +08:00
|
|
|
//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===//
|
|
|
|
//
|
|
|
|
// 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"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-12-01 17:51:01 +08:00
|
|
|
#include "clang/AST/ASTConsumer.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/AST/DeclVisitor.h"
|
2010-08-17 02:08:11 +08:00
|
|
|
#include "clang/AST/TypeOrdering.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/AST/StmtVisitor.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"
|
2010-08-19 07:57:17 +08:00
|
|
|
#include "clang/Serialization/ASTReader.h"
|
2010-08-19 07:56:37 +08:00
|
|
|
#include "clang/Serialization/ASTWriter.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2009-11-15 14:48:46 +08:00
|
|
|
#include "clang/Basic/TargetOptions.h"
|
2009-06-20 16:08:23 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2011-03-23 12:04:01 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2011-02-17 02:16:54 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2010-08-17 07:08:34 +08:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2010-12-07 08:05:48 +08:00
|
|
|
#include "llvm/Support/Atomic.h"
|
2010-01-23 08:14:00 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2010-11-30 02:12:39 +08:00
|
|
|
#include "llvm/Support/Host.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2010-08-10 04:45:32 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2010-07-31 04:58:08 +08:00
|
|
|
#include "llvm/Support/Timer.h"
|
2011-07-22 02:44:49 +08:00
|
|
|
#include "llvm/Support/FileSystem.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"
|
2011-03-18 10:06:56 +08:00
|
|
|
#include "llvm/Support/CrashRecoveryContext.h"
|
2010-07-23 08:33:23 +08:00
|
|
|
#include <cstdlib>
|
2010-07-23 10:15:08 +08:00
|
|
|
#include <cstdio>
|
2010-07-31 08:40:00 +08:00
|
|
|
#include <sys/stat.h>
|
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';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2011-10-28 01:55:18 +08:00
|
|
|
|
|
|
|
struct OnDiskData {
|
|
|
|
/// \brief The file in which the precompiled preamble is stored.
|
|
|
|
std::string PreambleFile;
|
|
|
|
|
|
|
|
/// \brief Temporary files that should be removed when the ASTUnit is
|
|
|
|
/// destroyed.
|
|
|
|
SmallVector<llvm::sys::Path, 4> TemporaryFiles;
|
|
|
|
|
|
|
|
/// \brief Erase temporary files.
|
|
|
|
void CleanTemporaryFiles();
|
|
|
|
|
|
|
|
/// \brief Erase the preamble file.
|
|
|
|
void CleanPreambleFile();
|
|
|
|
|
|
|
|
/// \brief Erase temporary files and the preamble file.
|
|
|
|
void Cleanup();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2011-10-28 03:44:25 +08:00
|
|
|
static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
|
|
|
|
static llvm::sys::SmartMutex<false> M(/* recursive = */ true);
|
|
|
|
return M;
|
|
|
|
}
|
|
|
|
|
2011-10-28 01:55:18 +08:00
|
|
|
static void cleanupOnDiskMapAtExit(void);
|
|
|
|
|
|
|
|
typedef llvm::DenseMap<const ASTUnit *, OnDiskData *> OnDiskDataMap;
|
|
|
|
static OnDiskDataMap &getOnDiskDataMap() {
|
|
|
|
static OnDiskDataMap M;
|
|
|
|
static bool hasRegisteredAtExit = false;
|
|
|
|
if (!hasRegisteredAtExit) {
|
|
|
|
hasRegisteredAtExit = true;
|
|
|
|
atexit(cleanupOnDiskMapAtExit);
|
|
|
|
}
|
|
|
|
return M;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cleanupOnDiskMapAtExit(void) {
|
2012-07-04 00:30:52 +08:00
|
|
|
// Use the mutex because there can be an alive thread destroying an ASTUnit.
|
|
|
|
llvm::MutexGuard Guard(getOnDiskMutex());
|
2011-10-28 01:55:18 +08:00
|
|
|
OnDiskDataMap &M = getOnDiskDataMap();
|
|
|
|
for (OnDiskDataMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
|
|
|
// We don't worry about freeing the memory associated with OnDiskDataMap.
|
|
|
|
// All we care about is erasing stale files.
|
|
|
|
I->second->Cleanup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static OnDiskData &getOnDiskData(const ASTUnit *AU) {
|
2011-10-28 03:44:25 +08:00
|
|
|
// We require the mutex since we are modifying the structure of the
|
|
|
|
// DenseMap.
|
|
|
|
llvm::MutexGuard Guard(getOnDiskMutex());
|
2011-10-28 01:55:18 +08:00
|
|
|
OnDiskDataMap &M = getOnDiskDataMap();
|
|
|
|
OnDiskData *&D = M[AU];
|
|
|
|
if (!D)
|
|
|
|
D = new OnDiskData();
|
|
|
|
return *D;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void erasePreambleFile(const ASTUnit *AU) {
|
|
|
|
getOnDiskData(AU).CleanPreambleFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void removeOnDiskEntry(const ASTUnit *AU) {
|
2011-10-28 03:44:25 +08:00
|
|
|
// We require the mutex since we are modifying the structure of the
|
|
|
|
// DenseMap.
|
|
|
|
llvm::MutexGuard Guard(getOnDiskMutex());
|
2011-10-28 01:55:18 +08:00
|
|
|
OnDiskDataMap &M = getOnDiskDataMap();
|
|
|
|
OnDiskDataMap::iterator I = M.find(AU);
|
|
|
|
if (I != M.end()) {
|
|
|
|
I->second->Cleanup();
|
|
|
|
delete I->second;
|
|
|
|
M.erase(AU);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setPreambleFile(const ASTUnit *AU, llvm::StringRef preambleFile) {
|
|
|
|
getOnDiskData(AU).PreambleFile = preambleFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const std::string &getPreambleFile(const ASTUnit *AU) {
|
|
|
|
return getOnDiskData(AU).PreambleFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnDiskData::CleanTemporaryFiles() {
|
|
|
|
for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
|
|
|
|
TemporaryFiles[I].eraseFromDisk();
|
|
|
|
TemporaryFiles.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnDiskData::CleanPreambleFile() {
|
|
|
|
if (!PreambleFile.empty()) {
|
|
|
|
llvm::sys::Path(PreambleFile).eraseFromDisk();
|
|
|
|
PreambleFile.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnDiskData::Cleanup() {
|
|
|
|
CleanTemporaryFiles();
|
|
|
|
CleanPreambleFile();
|
|
|
|
}
|
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
struct ASTUnit::ASTWriterData {
|
|
|
|
SmallString<128> Buffer;
|
|
|
|
llvm::BitstreamWriter Stream;
|
|
|
|
ASTWriter Writer;
|
|
|
|
|
|
|
|
ASTWriterData() : Stream(Buffer), Writer(Stream) { }
|
|
|
|
};
|
|
|
|
|
2011-10-31 15:19:59 +08:00
|
|
|
void ASTUnit::clearFileLevelDecls() {
|
|
|
|
for (FileDeclsTy::iterator
|
|
|
|
I = FileDecls.begin(), E = FileDecls.end(); I != E; ++I)
|
|
|
|
delete I->second;
|
|
|
|
FileDecls.clear();
|
|
|
|
}
|
|
|
|
|
2011-10-28 01:55:18 +08:00
|
|
|
void ASTUnit::CleanTemporaryFiles() {
|
|
|
|
getOnDiskData(this).CleanTemporaryFiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::addTemporaryFile(const llvm::sys::Path &TempFile) {
|
|
|
|
getOnDiskData(this).TemporaryFiles.push_back(TempFile);
|
2010-10-28 23:44: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.
|
2010-12-07 08:05:48 +08:00
|
|
|
static llvm::sys::cas_flag ActiveASTUnitObjects;
|
2010-11-17 08:13:31 +08:00
|
|
|
|
2010-04-06 05:10:19 +08:00
|
|
|
ASTUnit::ASTUnit(bool _MainFileIsAST)
|
2011-11-02 01:14:15 +08:00
|
|
|
: Reader(0), OnlyLocalDecls(false), CaptureDiagnostics(false),
|
2011-03-10 01:21: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),
|
2010-08-19 09:33:06 +08:00
|
|
|
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
|
2011-11-30 02:18:33 +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),
|
2010-08-19 08:45:44 +08:00
|
|
|
UnsafeToFree(false) {
|
2010-11-17 08:13:31 +08:00
|
|
|
if (getenv("LIBCLANG_OBJTRACKING")) {
|
2010-12-07 08:05:48 +08:00
|
|
|
llvm::sys::AtomicIncrement(&ActiveASTUnitObjects);
|
2010-11-17 08:13:31 +08:00
|
|
|
fprintf(stderr, "+++ %d 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() {
|
2011-10-31 15:19:59 +08:00
|
|
|
clearFileLevelDecls();
|
|
|
|
|
2011-10-28 01:55:18 +08:00
|
|
|
// Clean up the temporary files and the preamble file.
|
|
|
|
removeOnDiskEntry(this);
|
|
|
|
|
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.
|
2011-03-22 02:40:17 +08:00
|
|
|
if (Invocation.getPtr() && 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();
|
|
|
|
for (PreprocessorOptions::remapped_file_buffer_iterator
|
|
|
|
FB = PPOpts.remapped_file_buffer_begin(),
|
|
|
|
FBEnd = PPOpts.remapped_file_buffer_end();
|
|
|
|
FB != FBEnd;
|
|
|
|
++FB)
|
|
|
|
delete FB->second;
|
|
|
|
}
|
2010-07-27 22:52:07 +08:00
|
|
|
|
|
|
|
delete SavedMainFileBuffer;
|
2010-08-19 09:33:06 +08:00
|
|
|
delete PreambleBuffer;
|
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
ClearCachedCompletionResults();
|
2010-11-17 08:13:31 +08:00
|
|
|
|
|
|
|
if (getenv("LIBCLANG_OBJTRACKING")) {
|
2010-12-07 08:05:48 +08:00
|
|
|
llvm::sys::AtomicDecrement(&ActiveASTUnitObjects);
|
2010-11-17 08:13:31 +08:00
|
|
|
fprintf(stderr, "--- %d translation units\n", ActiveASTUnitObjects);
|
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
}
|
|
|
|
|
2012-01-18 02:48:07 +08:00
|
|
|
void ASTUnit::setPreprocessor(Preprocessor *pp) { PP = pp; }
|
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
/// \brief Determine the set of code-completion contexts in which this
|
|
|
|
/// declaration should be shown.
|
|
|
|
static unsigned getDeclShowContexts(NamedDecl *ND,
|
2010-08-17 07:05:20 +08:00
|
|
|
const LangOptions &LangOpts,
|
|
|
|
bool &IsNestedNameSpecifier) {
|
|
|
|
IsNestedNameSpecifier = false;
|
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
if (isa<UsingShadowDecl>(ND))
|
|
|
|
ND = dyn_cast<NamedDecl>(ND->getUnderlyingDecl());
|
|
|
|
if (!ND)
|
|
|
|
return 0;
|
|
|
|
|
2012-08-14 11:13:00 +08:00
|
|
|
uint64_t Contexts = 0;
|
2010-08-15 14:18:01 +08:00
|
|
|
if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND) ||
|
|
|
|
isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND)) {
|
|
|
|
// 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);
|
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);
|
2011-07-08 00:03:39 +08:00
|
|
|
|
|
|
|
// In Objective-C, you can only be a subclass of another Objective-C class
|
|
|
|
if (isa<ObjCInterfaceDecl>(ND))
|
2012-08-14 11:13:00 +08:00
|
|
|
Contexts |= (1LL << CodeCompletionContext::CCC_ObjCInterfaceName);
|
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);
|
2010-08-15 14:18:01 +08:00
|
|
|
|
2010-08-17 07:05:20 +08:00
|
|
|
// Part of the nested-name-specifier in C++0x.
|
2010-08-15 14:18:01 +08:00
|
|
|
if (LangOpts.CPlusPlus0x)
|
2010-08-17 07:05:20 +08:00
|
|
|
IsNestedNameSpecifier = true;
|
2010-08-15 14:18:01 +08:00
|
|
|
} else if (RecordDecl *Record = dyn_cast<RecordDecl>(ND)) {
|
|
|
|
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);
|
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);
|
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
|
|
|
}
|
|
|
|
|
|
|
|
return Contexts;
|
|
|
|
}
|
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
void ASTUnit::CacheCodeCompletionResults() {
|
|
|
|
if (!TheSema)
|
|
|
|
return;
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
// 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;
|
2011-02-17 03:08:06 +08:00
|
|
|
CachedCompletionAllocator = new GlobalCodeCompletionAllocator;
|
2012-04-11 01:23:48 +08:00
|
|
|
TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator,
|
|
|
|
getCodeCompletionTUInfo(), Results);
|
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;
|
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
for (unsigned I = 0, N = Results.size(); I != N; ++I) {
|
|
|
|
switch (Results[I].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;
|
2011-02-02 03:23:04 +08:00
|
|
|
CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema,
|
2012-04-11 01:23:48 +08:00
|
|
|
*CachedCompletionAllocator,
|
2012-07-03 01:35:10 +08:00
|
|
|
getCodeCompletionTUInfo(),
|
|
|
|
IncludeBriefCommentsInCodeCompletion);
|
2010-08-15 14:18:01 +08:00
|
|
|
CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration,
|
2012-03-11 15:00:24 +08:00
|
|
|
Ctx->getLangOpts(),
|
2010-08-17 07:05:20 +08:00
|
|
|
IsNestedNameSpecifier);
|
2010-08-15 14:18:01 +08:00
|
|
|
CachedResult.Priority = Results[I].Priority;
|
|
|
|
CachedResult.Kind = Results[I].CursorKind;
|
2010-08-24 07:00:57 +08:00
|
|
|
CachedResult.Availability = Results[I].Availability;
|
2010-08-17 00:46:30 +08:00
|
|
|
|
2010-08-17 02:08:11 +08:00
|
|
|
// Keep track of the type of this completion in an ASTContext-agnostic
|
|
|
|
// way.
|
2010-08-17 00:46:30 +08:00
|
|
|
QualType UsageType = getDeclUsageType(*Ctx, Results[I].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
|
|
|
|
// ourselves the work of formatting the type string by using the
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
CachedResult.Type = TypeValue;
|
2010-08-17 00:46:30 +08:00
|
|
|
}
|
2010-08-17 02:08:11 +08:00
|
|
|
|
2010-08-15 14:18:01 +08:00
|
|
|
CachedCompletionResults.push_back(CachedResult);
|
2010-08-17 07:05:20 +08:00
|
|
|
|
|
|
|
/// Handle nested-name-specifiers in C++.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (TheSema->Context.getLangOpts().CPlusPlus &&
|
2010-08-17 07:05:20 +08:00
|
|
|
IsNestedNameSpecifier && !Results[I].StartsNestedNameSpecifier) {
|
|
|
|
// 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
|
|
|
|
|
|
|
if (isa<NamespaceDecl>(Results[I].Declaration) ||
|
|
|
|
isa<NamespaceAliasDecl>(Results[I].Declaration))
|
2012-08-14 11:13:00 +08:00
|
|
|
NNSContexts |= (1LL << CodeCompletionContext::CCC_Namespace);
|
2010-08-17 07:05:20 +08:00
|
|
|
|
|
|
|
if (unsigned RemainingContexts
|
|
|
|
= NNSContexts & ~CachedResult.ShowInContexts) {
|
|
|
|
// If there any contexts where this completion can be a
|
|
|
|
// nested-name-specifier but isn't already an option, create a
|
|
|
|
// nested-name-specifier completion.
|
|
|
|
Results[I].StartsNestedNameSpecifier = true;
|
2011-02-02 03:23:04 +08:00
|
|
|
CachedResult.Completion
|
|
|
|
= Results[I].CreateCodeCompletionString(*TheSema,
|
2012-04-11 01:23:48 +08:00
|
|
|
*CachedCompletionAllocator,
|
2012-07-03 01:35:10 +08:00
|
|
|
getCodeCompletionTUInfo(),
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
case Result::RK_Macro: {
|
|
|
|
CachedCodeCompletionResult CachedResult;
|
2011-02-02 03:23:04 +08:00
|
|
|
CachedResult.Completion
|
|
|
|
= Results[I].CreateCodeCompletionString(*TheSema,
|
2012-04-11 01:23:48 +08:00
|
|
|
*CachedCompletionAllocator,
|
2012-07-03 01:35:10 +08:00
|
|
|
getCodeCompletionTUInfo(),
|
|
|
|
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);
|
2010-08-24 02:23:48 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
CachedResult.Priority = Results[I].Priority;
|
|
|
|
CachedResult.Kind = Results[I].CursorKind;
|
2010-08-24 07:00:57 +08:00
|
|
|
CachedResult.Availability = Results[I].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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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();
|
2011-02-17 03:08:06 +08:00
|
|
|
CachedCompletionAllocator = 0;
|
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;
|
2011-09-02 08:18:52 +08:00
|
|
|
ASTContext &Context;
|
2009-06-20 16:08:23 +08:00
|
|
|
LangOptions &LangOpt;
|
|
|
|
HeaderSearch &HSI;
|
2012-10-17 07:40:58 +08:00
|
|
|
IntrusiveRefCntPtr<TargetOptions> &TargetOpts;
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<TargetInfo> &Target;
|
2009-06-20 16:08:23 +08:00
|
|
|
std::string &Predefines;
|
|
|
|
unsigned &Counter;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
unsigned NumHeaderInfos;
|
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:
|
2011-09-02 08:18:52 +08:00
|
|
|
ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt,
|
2012-10-17 07:40:58 +08:00
|
|
|
HeaderSearch &HSI,
|
|
|
|
IntrusiveRefCntPtr<TargetOptions> &TargetOpts,
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<TargetInfo> &Target,
|
2011-09-02 07:39:15 +08:00
|
|
|
std::string &Predefines,
|
2009-06-20 16:08:23 +08:00
|
|
|
unsigned &Counter)
|
2012-10-16 00:45:32 +08:00
|
|
|
: PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI),
|
|
|
|
TargetOpts(TargetOpts), Target(Target),
|
2011-09-02 07:39:15 +08:00
|
|
|
Predefines(Predefines), Counter(Counter), NumHeaderInfos(0),
|
2011-09-02 08:18:52 +08:00
|
|
|
InitializedLanguage(false) {}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-10-10 10:12:47 +08:00
|
|
|
virtual bool ReadLanguageOptions(const serialization::ModuleFile &M,
|
|
|
|
const LangOptions &LangOpts) {
|
2012-10-12 00:05:00 +08:00
|
|
|
if (InitializedLanguage)
|
2011-09-02 07:39:15 +08:00
|
|
|
return false;
|
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
assert(M.Kind == serialization::MK_MainFile);
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
LangOpt = LangOpts;
|
2011-09-02 08:18:52 +08:00
|
|
|
InitializedLanguage = true;
|
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
|
|
|
|
2012-10-17 07:40:58 +08:00
|
|
|
virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
|
|
|
|
const TargetOptions &TargetOpts) {
|
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;
|
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
assert(M.Kind == serialization::MK_MainFile);
|
|
|
|
|
2012-10-17 07:40:58 +08:00
|
|
|
|
|
|
|
this->TargetOpts = new 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
|
|
|
|
2010-07-15 07:29:55 +08:00
|
|
|
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef OriginalFileName,
|
2011-02-24 05:16:44 +08:00
|
|
|
std::string &SuggestedPredefines,
|
|
|
|
FileManager &FileMgr) {
|
2010-07-15 07:29:55 +08:00
|
|
|
Predefines = Buffers[0].Data;
|
|
|
|
for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
|
|
|
|
Predefines += Buffers[I].Data;
|
|
|
|
}
|
2009-06-20 16:08:23 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-17 03:09:18 +08:00
|
|
|
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {
|
2009-06-20 16:08:23 +08:00
|
|
|
HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-10-10 10:12:47 +08:00
|
|
|
virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value) {
|
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.
|
|
|
|
Target->setForcedLangOptions(LangOpt);
|
|
|
|
|
|
|
|
// Initialize the preprocessor.
|
|
|
|
PP.Initialize(*Target);
|
|
|
|
|
|
|
|
// Initialize the ASTContext
|
|
|
|
Context.InitBuiltinTypes(*Target);
|
2012-09-15 04:24:53 +08:00
|
|
|
}
|
2009-06-20 16:08:23 +08:00
|
|
|
};
|
|
|
|
|
2011-09-26 08:01:39 +08:00
|
|
|
class StoredDiagnosticConsumer : public DiagnosticConsumer {
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<StoredDiagnostic> &StoredDiags;
|
2010-02-19 02:08:43 +08:00
|
|
|
|
|
|
|
public:
|
2011-09-26 08:01:39 +08:00
|
|
|
explicit StoredDiagnosticConsumer(
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<StoredDiagnostic> &StoredDiags)
|
2010-02-19 02:08:43 +08:00
|
|
|
: StoredDiags(StoredDiags) { }
|
|
|
|
|
2011-09-26 07:23:43 +08:00
|
|
|
virtual void HandleDiagnostic(DiagnosticsEngine::Level Level,
|
2011-09-26 09:18:08 +08:00
|
|
|
const Diagnostic &Info);
|
2011-09-29 08:38:00 +08:00
|
|
|
|
|
|
|
DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
|
|
|
|
// Just drop any diagnostics that come from cloned consumers; they'll
|
|
|
|
// have different source managers anyway.
|
2012-01-30 03:57:03 +08:00
|
|
|
// FIXME: We'd like to be able to capture these somehow, even if it's just
|
|
|
|
// file/line/column, because they could occur when parsing module maps or
|
|
|
|
// building modules on-demand.
|
2011-09-29 08:38:00 +08:00
|
|
|
return new IgnoringDiagConsumer();
|
|
|
|
}
|
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;
|
2010-02-19 02:08:43 +08:00
|
|
|
|
|
|
|
public:
|
2011-09-26 07:23:43 +08:00
|
|
|
CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags,
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVectorImpl<StoredDiagnostic> &StoredDiags)
|
2010-08-19 06:29:43 +08:00
|
|
|
: Diags(Diags), Client(StoredDiags), PreviousClient(0)
|
2010-02-19 02:08:43 +08:00
|
|
|
{
|
2010-08-19 06:29:43 +08:00
|
|
|
if (RequestCapture || Diags.getClient() == 0) {
|
|
|
|
PreviousClient = Diags.takeClient();
|
2010-02-19 02:08:43 +08:00
|
|
|
Diags.setClient(&Client);
|
2010-08-19 06:29:43 +08:00
|
|
|
}
|
2010-02-19 02:08:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
~CaptureDroppedDiagnostics() {
|
2010-08-19 06:29:43 +08:00
|
|
|
if (Diags.getClient() == &Client) {
|
|
|
|
Diags.takeClient();
|
|
|
|
Diags.setClient(PreviousClient);
|
|
|
|
}
|
2010-02-19 02:08:43 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2011-09-26 08:01:39 +08:00
|
|
|
void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level,
|
2011-09-26 09:18:08 +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
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
StoredDiags.push_back(StoredDiagnostic(Level, Info));
|
|
|
|
}
|
|
|
|
|
2009-09-04 02:19:54 +08:00
|
|
|
const std::string &ASTUnit::getOriginalSourceFileName() {
|
2009-12-02 16:44:16 +08:00
|
|
|
return OriginalSourceFile;
|
2009-09-04 02:19:54 +08:00
|
|
|
}
|
2009-06-20 16:08:23 +08:00
|
|
|
|
2012-10-12 00:05:00 +08:00
|
|
|
ASTDeserializationListener *ASTUnit::getDeserializationListener() {
|
|
|
|
if (WriterData)
|
|
|
|
return &WriterData->Writer;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename,
|
2010-11-23 17:19:42 +08:00
|
|
|
std::string *ErrorStr) {
|
2010-11-23 16:35:12 +08:00
|
|
|
assert(FileMgr);
|
2010-11-23 17:19:42 +08:00
|
|
|
return FileMgr->getBufferForFile(Filename, ErrorStr);
|
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.
|
2012-02-20 22:00:23 +08:00
|
|
|
void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
|
2011-01-19 09:02:47 +08:00
|
|
|
const char **ArgBegin, const char **ArgEnd,
|
2010-11-11 08:39:14 +08:00
|
|
|
ASTUnit &AST, bool CaptureDiagnostics) {
|
|
|
|
if (!Diags.getPtr()) {
|
|
|
|
// No diagnostics engine was provided, so create our own diagnostics object
|
|
|
|
// with the default options.
|
|
|
|
DiagnosticOptions DiagOpts;
|
2011-09-26 07:39:51 +08:00
|
|
|
DiagnosticConsumer *Client = 0;
|
2010-11-11 08:39:14 +08:00
|
|
|
if (CaptureDiagnostics)
|
2011-09-26 08:01:39 +08:00
|
|
|
Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
|
2012-04-14 17:11:56 +08:00
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd-ArgBegin,
|
|
|
|
ArgBegin, Client,
|
|
|
|
/*ShouldOwnClient=*/true,
|
|
|
|
/*ShouldCloneClient=*/false);
|
2010-11-11 08:39:14 +08:00
|
|
|
} else if (CaptureDiagnostics) {
|
2011-09-26 08:01:39 +08:00
|
|
|
Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics));
|
2010-11-11 08:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:06 +08:00
|
|
|
ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
2010-11-04 06:45:23 +08:00
|
|
|
const FileSystemOptions &FileSystemOpts,
|
2009-10-17 08:34:24 +08:00
|
|
|
bool OnlyLocalDecls,
|
2010-01-23 08:14:00 +08:00
|
|
|
RemappedFile *RemappedFiles,
|
2010-02-19 02:08:43 +08:00
|
|
|
unsigned NumRemappedFiles,
|
2012-03-07 09:51:17 +08:00
|
|
|
bool CaptureDiagnostics,
|
2012-07-12 04:59:04 +08:00
|
|
|
bool AllowPCHWithCompilerErrors,
|
|
|
|
bool UserFilesAreVolatile) {
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<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> >
|
2011-03-22 09:15:24 +08:00
|
|
|
DiagCleanup(Diags.getPtr());
|
2011-03-18 10:06:56 +08:00
|
|
|
|
2011-01-19 09:02:47 +08:00
|
|
|
ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
|
2010-07-20 05:46:24 +08:00
|
|
|
|
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;
|
2011-03-22 02:40:17 +08:00
|
|
|
AST->FileMgr = new FileManager(FileSystemOpts);
|
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);
|
2011-11-11 08:35:06 +08:00
|
|
|
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(),
|
2011-12-31 12:05:44 +08:00
|
|
|
AST->getDiagnostics(),
|
2012-01-30 14:01:29 +08:00
|
|
|
AST->ASTFileLangOpts,
|
|
|
|
/*Target=*/0));
|
2010-08-13 11:15:25 +08:00
|
|
|
|
2010-01-23 08:14:00 +08:00
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
|
2011-03-05 09:03:53 +08:00
|
|
|
FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
|
|
|
|
if (const llvm::MemoryBuffer *
|
|
|
|
memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
|
|
|
|
// Create the file entry for the file that we're mapping from.
|
|
|
|
const FileEntry *FromFile
|
|
|
|
= AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
|
|
|
|
memBuf->getBufferSize(),
|
|
|
|
0);
|
|
|
|
if (!FromFile) {
|
|
|
|
AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
|
|
|
|
<< RemappedFiles[I].first;
|
|
|
|
delete memBuf;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override the contents of the "from" file with the contents of
|
|
|
|
// the "to" file.
|
|
|
|
AST->getSourceManager().overrideFileContents(FromFile, memBuf);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
const char *fname = fileOrBuf.get<const char *>();
|
|
|
|
const FileEntry *ToFile = AST->FileMgr->getFile(fname);
|
|
|
|
if (!ToFile) {
|
|
|
|
AST->getDiagnostics().Report(diag::err_fe_remap_missing_to_file)
|
|
|
|
<< RemappedFiles[I].first << fname;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the file entry for the file that we're mapping from.
|
|
|
|
const FileEntry *FromFile
|
|
|
|
= AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
|
|
|
|
ToFile->getSize(),
|
|
|
|
0);
|
|
|
|
if (!FromFile) {
|
|
|
|
AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
|
|
|
|
<< RemappedFiles[I].first;
|
|
|
|
delete memBuf;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override the contents of the "from" file with the contents of
|
|
|
|
// the "to" file.
|
|
|
|
AST->getSourceManager().overrideFileContents(FromFile, ToFile);
|
2010-01-23 08:14:00 +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
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
|
|
|
|
std::string Predefines;
|
|
|
|
unsigned Counter;
|
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<ASTReader> Reader;
|
2009-06-20 16:08:23 +08:00
|
|
|
|
2011-09-02 07:39:15 +08:00
|
|
|
AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts,
|
|
|
|
/*Target=*/0, AST->getSourceManager(), HeaderInfo,
|
|
|
|
*AST,
|
|
|
|
/*IILookup=*/0,
|
|
|
|
/*OwnsHeaderSearch=*/false,
|
|
|
|
/*DelayInitialization=*/true);
|
2011-09-02 08:18:52 +08:00
|
|
|
Preprocessor &PP = *AST->PP;
|
|
|
|
|
|
|
|
AST->Ctx = new ASTContext(AST->ASTFileLangOpts,
|
|
|
|
AST->getSourceManager(),
|
|
|
|
/*Target=*/0,
|
|
|
|
PP.getIdentifierTable(),
|
|
|
|
PP.getSelectorTable(),
|
|
|
|
PP.getBuiltinInfo(),
|
|
|
|
/* size_reserve = */0,
|
|
|
|
/*DelayInitialization=*/true);
|
|
|
|
ASTContext &Context = *AST->Ctx;
|
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;
|
2012-03-07 09:51:17 +08:00
|
|
|
Reader.reset(new ASTReader(PP, Context,
|
|
|
|
/*isysroot=*/"",
|
2012-09-15 09:10:20 +08:00
|
|
|
/*DisableValidation=*/disableValid,
|
2012-03-07 09:51:17 +08:00
|
|
|
/*DisableStatCache=*/false,
|
|
|
|
AllowPCHWithCompilerErrors));
|
2011-05-05 07:27:12 +08:00
|
|
|
|
|
|
|
// Recover resources if we crash before exiting this method.
|
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<ASTReader>
|
|
|
|
ReaderCleanup(Reader.get());
|
|
|
|
|
2011-09-02 08:18:52 +08:00
|
|
|
Reader->setListener(new ASTInfoCollector(*AST->PP, Context,
|
2011-09-02 07:39:15 +08:00
|
|
|
AST->ASTFileLangOpts, HeaderInfo,
|
2012-10-16 00:45:32 +08:00
|
|
|
AST->TargetOpts, AST->Target,
|
|
|
|
Predefines, Counter));
|
2009-09-03 13:59:35 +08:00
|
|
|
|
2011-07-23 00:00:58 +08:00
|
|
|
switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) {
|
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:
|
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);
|
2009-06-20 16:08:23 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-12-02 16:44:16 +08:00
|
|
|
AST->OriginalSourceFile = Reader->getOriginalSourceFile();
|
|
|
|
|
2009-09-21 11:03:47 +08:00
|
|
|
PP.setPredefines(Reader->getSuggestedPredefines());
|
2009-06-20 16:08:23 +08:00
|
|
|
PP.setCounterValue(Counter);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-19 07:56:43 +08:00
|
|
|
// Attach the AST reader to the AST context as an external AST
|
2009-06-20 16:08:23 +08:00
|
|
|
// source, so that declarations will be deserialized from the
|
2010-08-19 07:57:06 +08:00
|
|
|
// AST file as needed.
|
2010-08-19 07:56:43 +08:00
|
|
|
ASTReader *ReaderPtr = Reader.get();
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<ExternalASTSource> Source(Reader.take());
|
2011-05-05 07:27:12 +08:00
|
|
|
|
|
|
|
// Unregister the cleanup for ASTReader. It will get cleaned up
|
|
|
|
// by the ASTUnit cleanup.
|
|
|
|
ReaderCleanup.unregister();
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
Context.setExternalSource(Source);
|
|
|
|
|
2010-08-13 11:15:25 +08:00
|
|
|
// Create an AST consumer, even though it isn't used.
|
|
|
|
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.
|
2010-08-13 11:15:25 +08:00
|
|
|
AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer));
|
|
|
|
AST->TheSema->Initialize();
|
|
|
|
ReaderPtr->InitializeSema(*AST->TheSema);
|
2011-11-02 01:14:15 +08:00
|
|
|
AST->Reader = ReaderPtr;
|
2010-08-13 11:15:25 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
return AST.take();
|
2009-06-20 16:08:23 +08:00
|
|
|
}
|
2009-12-01 17:51:01 +08:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2011-02-17 02:16:54 +08:00
|
|
|
/// \brief Preprocessor callback class that updates a hash value with the names
|
|
|
|
/// of all macros that have been defined by the translation unit.
|
|
|
|
class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
|
|
|
|
unsigned &Hash;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { }
|
|
|
|
|
|
|
|
virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
|
|
|
|
Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// \brief Add the given declaration to the hash of all top-level entities.
|
|
|
|
void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
|
|
|
|
if (!D)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DeclContext *DC = D->getDeclContext();
|
|
|
|
if (!DC)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!(DC->isTranslationUnit() || DC->getLookupParent()->isTranslationUnit()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
|
|
|
|
if (ND->getIdentifier())
|
|
|
|
Hash = llvm::HashString(ND->getIdentifier()->getName(), Hash);
|
|
|
|
else if (DeclarationName Name = ND->getDeclName()) {
|
|
|
|
std::string NameStr = Name.getAsString();
|
|
|
|
Hash = llvm::HashString(NameStr, Hash);
|
|
|
|
}
|
|
|
|
return;
|
2012-01-02 05:23:57 +08:00
|
|
|
}
|
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;
|
|
|
|
|
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)) {
|
|
|
|
for (NamespaceDecl::decl_iterator
|
|
|
|
I = NSD->decls_begin(), E = NSD->decls_end(); I != E; ++I)
|
|
|
|
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
|
|
|
|
2011-11-18 08:26:59 +08:00
|
|
|
bool HandleTopLevelDecl(DeclGroupRef D) {
|
2011-10-31 15:19:59 +08:00
|
|
|
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
|
|
|
|
handleTopLevelDecl(*it);
|
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.
|
|
|
|
void HandleInterestingDecl(DeclGroupRef) {}
|
2011-10-31 15:19:59 +08:00
|
|
|
|
|
|
|
void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
|
|
|
|
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it)
|
|
|
|
handleTopLevelDecl(*it);
|
|
|
|
}
|
2012-10-12 00:05:00 +08:00
|
|
|
|
|
|
|
virtual ASTDeserializationListener *GetASTDeserializationListener() {
|
|
|
|
return Unit.getDeserializationListener();
|
|
|
|
}
|
2009-12-04 16:17:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class TopLevelDeclTrackerAction : public ASTFrontendAction {
|
|
|
|
public:
|
|
|
|
ASTUnit &Unit;
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef InFile) {
|
2011-02-17 02:16:54 +08:00
|
|
|
CI.getPreprocessor().addPPCallbacks(
|
|
|
|
new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
|
|
|
|
return new 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) {}
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
virtual bool hasCodeCompletionSupport() const { return false; }
|
2011-08-26 06:30:56 +08:00
|
|
|
virtual TranslationUnitKind getTranslationUnitKind() {
|
|
|
|
return Unit.getTranslationUnitKind();
|
2010-08-10 04:45:32 +08:00
|
|
|
}
|
2009-12-01 17:51:01 +08:00
|
|
|
};
|
|
|
|
|
2011-09-20 04:40:48 +08:00
|
|
|
class PrecompilePreambleConsumer : public PCHGenerator {
|
2010-08-03 16:14:03 +08:00
|
|
|
ASTUnit &Unit;
|
2011-02-17 02:16:54 +08:00
|
|
|
unsigned &Hash;
|
2010-08-04 03:06:41 +08:00
|
|
|
std::vector<Decl *> TopLevelDecls;
|
2010-11-30 14:16:57 +08:00
|
|
|
|
2010-08-03 16:14:03 +08:00
|
|
|
public:
|
2011-08-26 06:35:51 +08:00
|
|
|
PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef isysroot, raw_ostream *Out)
|
2011-11-30 12:39:39 +08:00
|
|
|
: PCHGenerator(PP, "", 0, isysroot, Out), Unit(Unit),
|
2011-02-17 02:16:54 +08:00
|
|
|
Hash(Unit.getCurrentTopLevelHashValue()) {
|
|
|
|
Hash = 0;
|
|
|
|
}
|
2010-08-03 16:14:03 +08:00
|
|
|
|
2011-11-18 08:26:59 +08:00
|
|
|
virtual bool HandleTopLevelDecl(DeclGroupRef D) {
|
2010-08-03 16:14:03 +08:00
|
|
|
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
|
|
|
|
Decl *D = *it;
|
|
|
|
// 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);
|
|
|
|
}
|
2011-11-18 08:26:59 +08:00
|
|
|
return true;
|
2010-08-04 03:06:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void HandleTranslationUnit(ASTContext &Ctx) {
|
|
|
|
PCHGenerator::HandleTranslationUnit(Ctx);
|
|
|
|
if (!Unit.getDiagnostics().hasErrorOccurred()) {
|
|
|
|
// Translate the top-level declarations we captured during
|
|
|
|
// parsing into declaration IDs in the precompiled
|
|
|
|
// preamble. This will allow us to deserialize those top-level
|
|
|
|
// declarations when requested.
|
|
|
|
for (unsigned I = 0, N = TopLevelDecls.size(); I != N; ++I)
|
|
|
|
Unit.addTopLevelDeclFromPreamble(
|
|
|
|
getWriter().getDeclID(TopLevelDecls[I]));
|
2010-08-03 16:14:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class PrecompilePreambleAction : public ASTFrontendAction {
|
|
|
|
ASTUnit &Unit;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {}
|
|
|
|
|
|
|
|
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef InFile) {
|
2010-08-03 16:14:03 +08:00
|
|
|
std::string Sysroot;
|
2011-02-16 01:54:22 +08:00
|
|
|
std::string OutputFile;
|
2011-07-23 18:55:15 +08:00
|
|
|
raw_ostream *OS = 0;
|
2011-02-16 01:54:22 +08:00
|
|
|
if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
|
|
|
|
OutputFile,
|
2011-08-26 06:35:51 +08:00
|
|
|
OS))
|
2010-08-03 16:14:03 +08:00
|
|
|
return 0;
|
|
|
|
|
2011-07-23 00:35:34 +08:00
|
|
|
if (!CI.getFrontendOpts().RelocatablePCH)
|
|
|
|
Sysroot.clear();
|
|
|
|
|
2011-02-17 02:16:54 +08:00
|
|
|
CI.getPreprocessor().addPPCallbacks(
|
|
|
|
new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
|
2011-08-26 06:35:51 +08:00
|
|
|
return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Sysroot,
|
|
|
|
OS);
|
2010-08-03 16:14:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool hasCodeCompletionSupport() const { return false; }
|
|
|
|
virtual bool hasASTFileSupport() const { return false; }
|
2011-08-26 06:30:56 +08:00
|
|
|
virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; }
|
2010-08-03 16:14:03 +08:00
|
|
|
};
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
}
|
|
|
|
|
2012-02-02 03:54:02 +08:00
|
|
|
static void checkAndRemoveNonDriverDiags(SmallVectorImpl<StoredDiagnostic> &
|
|
|
|
StoredDiagnostics) {
|
|
|
|
// Get rid of stored diagnostics except the ones from the driver which do not
|
|
|
|
// have a source location.
|
|
|
|
for (unsigned I = 0; I < StoredDiagnostics.size(); ++I) {
|
|
|
|
if (StoredDiagnostics[I].getLocation().isValid()) {
|
|
|
|
StoredDiagnostics.erase(StoredDiagnostics.begin()+I);
|
|
|
|
--I;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
for (unsigned I = 0, N = StoredDiagnostics.size(); I < N; ++I) {
|
|
|
|
if (StoredDiagnostics[I].getLocation().isValid()) {
|
|
|
|
FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SM);
|
|
|
|
StoredDiagnostics[I].setLocation(Loc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
2010-07-24 08:38:13 +08:00
|
|
|
bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
|
2010-07-27 22:52:07 +08:00
|
|
|
delete SavedMainFileBuffer;
|
|
|
|
SavedMainFileBuffer = 0;
|
|
|
|
|
2011-03-22 02:40:17 +08:00
|
|
|
if (!Invocation) {
|
2010-08-19 09:33:06 +08:00
|
|
|
delete OverrideMainBuffer;
|
2010-07-20 05:46:24 +08:00
|
|
|
return true;
|
2010-08-19 09:33:06 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the compiler instance to use for building the AST.
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
|
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
|
|
|
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<CompilerInvocation>
|
2011-09-13 02:09:38 +08:00
|
|
|
CCInvocation(new CompilerInvocation(*Invocation));
|
|
|
|
|
|
|
|
Clang->setInvocation(CCInvocation.getPtr());
|
2012-01-21 00:28:04 +08:00
|
|
|
OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
|
2010-07-20 05:46:24 +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());
|
2010-04-06 05:10:19 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the target instance.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
|
2011-03-22 02:40:17 +08:00
|
|
|
Clang->getTargetOpts()));
|
2011-03-22 02:40:07 +08:00
|
|
|
if (!Clang->hasTarget()) {
|
2010-08-19 09:33:06 +08:00
|
|
|
delete OverrideMainBuffer;
|
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.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
|
2010-07-20 05:46:24 +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!");
|
2012-01-21 00:28:04 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
|
2009-12-01 17:51:01 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2012-01-21 00:28:04 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_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.
|
|
|
|
// FIXME: Should we retain the previous file manager?
|
2011-11-18 07:01:24 +08:00
|
|
|
LangOpts = &Clang->getLangOpts();
|
2011-03-22 02:40:07 +08:00
|
|
|
FileSystemOpts = Clang->getFileSystemOpts();
|
2011-03-22 02:40:17 +08:00
|
|
|
FileMgr = new FileManager(FileSystemOpts);
|
2012-07-12 04:59:04 +08:00
|
|
|
SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
|
|
|
|
UserFilesAreVolatile);
|
2010-08-13 11:15:25 +08:00
|
|
|
TheSema.reset();
|
2011-03-22 02:40:17 +08:00
|
|
|
Ctx = 0;
|
|
|
|
PP = 0;
|
2011-11-02 01:14:15 +08:00
|
|
|
Reader = 0;
|
2010-07-20 05:46:24 +08:00
|
|
|
|
|
|
|
// Clear out old caches and data.
|
|
|
|
TopLevelDecls.clear();
|
2011-10-31 15:19:59 +08:00
|
|
|
clearFileLevelDecls();
|
2010-07-20 05:46:24 +08:00
|
|
|
CleanTemporaryFiles();
|
2010-08-03 04:51:39 +08:00
|
|
|
|
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());
|
2010-07-20 05:46:24 +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());
|
2010-07-20 05:46:24 +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.
|
2011-03-22 02:40:07 +08:00
|
|
|
PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
|
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 (OverrideMainBuffer) {
|
|
|
|
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.second
|
|
|
|
= PreambleEndsAtStartOfLine;
|
2011-10-28 01:55:18 +08:00
|
|
|
PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
|
2010-07-27 08:27:13 +08:00
|
|
|
PreprocessorOpts.DisablePCHValidation = true;
|
2010-07-27 22:52:07 +08:00
|
|
|
|
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;
|
|
|
|
SavedMainFileBuffer = 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
|
|
|
}
|
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<TopLevelDeclTrackerAction> Act(
|
2011-03-22 09:15:24 +08:00
|
|
|
new TopLevelDeclTrackerAction(*this));
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
if (OverrideMainBuffer) {
|
2011-10-28 01:55:18 +08:00
|
|
|
std::string ModName = getPreambleFile(this);
|
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
|
|
|
TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
|
|
|
|
getSourceManager(), PreambleDiagnostics,
|
|
|
|
StoredDiagnostics);
|
|
|
|
}
|
|
|
|
|
2012-06-08 13:48:06 +08:00
|
|
|
if (!Act->Execute())
|
|
|
|
goto error;
|
2012-04-11 10:11:16 +08:00
|
|
|
|
|
|
|
transferASTDataFromCompilerInstance(*Clang);
|
2010-07-20 05:46:24 +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.
|
2010-07-27 08:27:13 +08:00
|
|
|
if (OverrideMainBuffer) {
|
2010-08-19 09:33:06 +08:00
|
|
|
delete OverrideMainBuffer;
|
2010-10-07 05:11:08 +08:00
|
|
|
SavedMainFileBuffer = 0;
|
2010-07-27 08:27:13 +08:00
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
2010-07-23 08:33:23 +08:00
|
|
|
/// \brief Simple function to retrieve a path for a preamble precompiled header.
|
|
|
|
static std::string GetPreamblePCHPath() {
|
|
|
|
// FIXME: This is lame; sys::Path should provide this function (in particular,
|
|
|
|
// it should know how to find the temporary files dir).
|
|
|
|
// FIXME: This is really lame. I copied this code from the Driver!
|
2010-09-12 02:05:19 +08:00
|
|
|
// FIXME: This is a hack so that we can override the preamble file during
|
|
|
|
// crash-recovery testing, which is the only case where the preamble files
|
|
|
|
// are not necessarily cleaned up.
|
|
|
|
const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE");
|
|
|
|
if (TmpFile)
|
|
|
|
return TmpFile;
|
|
|
|
|
2010-07-23 08:33:23 +08:00
|
|
|
std::string Error;
|
|
|
|
const char *TmpDir = ::getenv("TMPDIR");
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = ::getenv("TEMP");
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = ::getenv("TMP");
|
2010-09-12 01:51:16 +08:00
|
|
|
#ifdef LLVM_ON_WIN32
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = ::getenv("USERPROFILE");
|
|
|
|
#endif
|
2010-07-23 08:33:23 +08:00
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = "/tmp";
|
|
|
|
llvm::sys::Path P(TmpDir);
|
2010-09-12 01:51:16 +08:00
|
|
|
P.createDirectoryOnDisk(true);
|
2010-07-23 08:33:23 +08:00
|
|
|
P.appendComponent("preamble");
|
2010-08-11 21:06:56 +08:00
|
|
|
P.appendSuffix("pch");
|
2011-07-22 02:44:46 +08:00
|
|
|
if (P.makeUnique(/*reuse_current=*/false, /*ErrMsg*/0))
|
2010-07-23 08:33:23 +08:00
|
|
|
return std::string();
|
|
|
|
|
|
|
|
return P.str();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
/// \brief Compute the preamble for the main file, providing the source buffer
|
|
|
|
/// that corresponds to the main file along with a pair (bytes, start-of-line)
|
|
|
|
/// that describes the preamble.
|
|
|
|
std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> >
|
2010-08-10 04:45:32 +08:00
|
|
|
ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
|
|
|
|
unsigned MaxLines, bool &CreatedBuffer) {
|
2010-07-24 07:58:40 +08:00
|
|
|
FrontendOptions &FrontendOpts = Invocation.getFrontendOpts();
|
2010-11-23 16:35:12 +08:00
|
|
|
PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts();
|
2010-07-24 07:58:40 +08:00
|
|
|
CreatedBuffer = false;
|
|
|
|
|
2010-07-23 08:33:23 +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).
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::MemoryBuffer *Buffer = 0;
|
2012-01-21 00:28:04 +08:00
|
|
|
llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File);
|
2010-07-23 08:33:23 +08:00
|
|
|
if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) {
|
|
|
|
// Check whether there is a file-file remapping of the main file
|
|
|
|
for (PreprocessorOptions::remapped_file_iterator
|
2010-07-24 07:58:40 +08:00
|
|
|
M = PreprocessorOpts.remapped_file_begin(),
|
|
|
|
E = PreprocessorOpts.remapped_file_end();
|
2010-07-23 08:33:23 +08:00
|
|
|
M != E;
|
|
|
|
++M) {
|
|
|
|
llvm::sys::PathWithStatus MPath(M->first);
|
|
|
|
if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
|
|
|
|
if (MainFileStatus->uniqueID == MStatus->uniqueID) {
|
|
|
|
// We found a remapping. Try to load the resulting, remapped source.
|
2010-07-24 07:58:40 +08:00
|
|
|
if (CreatedBuffer) {
|
2010-07-23 08:33:23 +08:00
|
|
|
delete Buffer;
|
2010-07-24 07:58:40 +08:00
|
|
|
CreatedBuffer = false;
|
|
|
|
}
|
|
|
|
|
2010-11-04 06:45:23 +08:00
|
|
|
Buffer = getBufferForFile(M->second);
|
2010-07-23 08:33:23 +08:00
|
|
|
if (!Buffer)
|
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
|
|
|
return std::make_pair((llvm::MemoryBuffer*)0,
|
|
|
|
std::make_pair(0, true));
|
2010-07-24 07:58:40 +08:00
|
|
|
CreatedBuffer = true;
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether there is a file-buffer remapping. It supercedes the
|
|
|
|
// file-file remapping.
|
|
|
|
for (PreprocessorOptions::remapped_file_buffer_iterator
|
|
|
|
M = PreprocessorOpts.remapped_file_buffer_begin(),
|
|
|
|
E = PreprocessorOpts.remapped_file_buffer_end();
|
|
|
|
M != E;
|
|
|
|
++M) {
|
|
|
|
llvm::sys::PathWithStatus MPath(M->first);
|
|
|
|
if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) {
|
|
|
|
if (MainFileStatus->uniqueID == MStatus->uniqueID) {
|
|
|
|
// We found a remapping.
|
2010-07-24 07:58:40 +08:00
|
|
|
if (CreatedBuffer) {
|
2010-07-23 08:33:23 +08:00
|
|
|
delete Buffer;
|
2010-07-24 07:58:40 +08:00
|
|
|
CreatedBuffer = false;
|
|
|
|
}
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
Buffer = const_cast<llvm::MemoryBuffer *>(M->second);
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
}
|
2010-07-24 07:58:40 +08:00
|
|
|
}
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the main source file was not remapped, load it now.
|
|
|
|
if (!Buffer) {
|
2012-01-21 00:28:04 +08:00
|
|
|
Buffer = getBufferForFile(FrontendOpts.Inputs[0].File);
|
2010-07-23 08:33:23 +08:00
|
|
|
if (!Buffer)
|
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
|
|
|
return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));
|
2010-07-24 07:58:40 +08:00
|
|
|
|
|
|
|
CreatedBuffer = true;
|
|
|
|
}
|
|
|
|
|
2011-08-26 04:39:19 +08:00
|
|
|
return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer,
|
2011-11-18 07:01:24 +08:00
|
|
|
*Invocation.getLangOpts(),
|
2011-08-26 04:39:19 +08:00
|
|
|
MaxLines));
|
2010-07-24 07:58:40 +08:00
|
|
|
}
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old,
|
|
|
|
unsigned NewSize,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef NewName) {
|
2010-07-24 08:38:13 +08:00
|
|
|
llvm::MemoryBuffer *Result
|
|
|
|
= llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName);
|
|
|
|
memcpy(const_cast<char*>(Result->getBufferStart()),
|
|
|
|
Old->getBufferStart(), Old->getBufferSize());
|
|
|
|
memset(const_cast<char*>(Result->getBufferStart()) + Old->getBufferSize(),
|
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
|
|
|
' ', NewSize - Old->getBufferSize() - 1);
|
|
|
|
const_cast<char*>(Result->getBufferEnd())[-1] = '\n';
|
2010-07-24 08:38:13 +08:00
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
/// non-trivial preamble is found, it will precompile that preamble into a
|
|
|
|
/// precompiled header so that the precompiled preamble can be used to reduce
|
|
|
|
/// reparsing time. If a precompiled preamble has already been constructed,
|
|
|
|
/// this routine will determine if it is still valid and, if so, avoid
|
|
|
|
/// 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.
|
2010-08-10 04:45:32 +08:00
|
|
|
llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
|
2011-07-02 02:22:13 +08:00
|
|
|
const CompilerInvocation &PreambleInvocationIn,
|
2010-08-10 04:45:32 +08:00
|
|
|
bool AllowRebuild,
|
|
|
|
unsigned MaxLines) {
|
2011-07-02 02:22:13 +08:00
|
|
|
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<CompilerInvocation>
|
2011-07-02 02:22:13 +08:00
|
|
|
PreambleInvocation(new CompilerInvocation(PreambleInvocationIn));
|
|
|
|
FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts();
|
2010-07-24 07:58:40 +08:00
|
|
|
PreprocessorOptions &PreprocessorOpts
|
2011-07-02 02:22:13 +08:00
|
|
|
= PreambleInvocation->getPreprocessorOpts();
|
2010-07-24 07:58:40 +08:00
|
|
|
|
|
|
|
bool CreatedPreambleBuffer = false;
|
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
|
|
|
std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > NewPreamble
|
2011-07-02 02:22:13 +08:00
|
|
|
= ComputePreamble(*PreambleInvocation, MaxLines, CreatedPreambleBuffer);
|
2010-07-24 07:58:40 +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
|
|
|
// If ComputePreamble() Take ownership of the preamble buffer.
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer;
|
2010-11-17 04:45:51 +08:00
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
OwnedPreambleBuffer.reset(NewPreamble.first);
|
|
|
|
|
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 (!NewPreamble.second.first) {
|
2010-07-24 07:58:40 +08:00
|
|
|
// We couldn't find a preamble in the main source. Clear out the current
|
|
|
|
// preamble, if we have one. It's obviously no good any more.
|
|
|
|
Preamble.clear();
|
2011-10-28 01:55:18 +08:00
|
|
|
erasePreambleFile(this);
|
2010-08-04 13:53:38 +08:00
|
|
|
|
|
|
|
// The next time we actually see a preamble, precompile it.
|
|
|
|
PreambleRebuildCounter = 1;
|
2010-07-24 08:38:13 +08:00
|
|
|
return 0;
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
if (!Preamble.empty()) {
|
|
|
|
// We've previously computed a preamble. Check whether we have the same
|
|
|
|
// preamble now that we did before, and that there's enough space in
|
|
|
|
// the main-file buffer within the precompiled preamble to fit the
|
|
|
|
// new main file.
|
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 (Preamble.size() == NewPreamble.second.first &&
|
|
|
|
PreambleEndsAtStartOfLine == NewPreamble.second.second &&
|
2010-07-24 08:42:07 +08:00
|
|
|
NewPreamble.first->getBufferSize() < PreambleReservedSize-2 &&
|
2011-09-20 04:40:35 +08:00
|
|
|
memcmp(Preamble.getBufferStart(), NewPreamble.first->getBufferStart(),
|
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
|
|
|
NewPreamble.second.first) == 0) {
|
2010-07-24 07:58:40 +08:00
|
|
|
// The preamble has not changed. We may be able to re-use the precompiled
|
|
|
|
// preamble.
|
2010-08-03 04:51:39 +08:00
|
|
|
|
2010-07-31 08:40:00 +08:00
|
|
|
// Check that none of the files used by the preamble have changed.
|
|
|
|
bool AnyFileChanged = false;
|
|
|
|
|
|
|
|
// First, make a record of those files that have been overridden via
|
|
|
|
// remapping or unsaved_files.
|
|
|
|
llvm::StringMap<std::pair<off_t, time_t> > OverriddenFiles;
|
|
|
|
for (PreprocessorOptions::remapped_file_iterator
|
|
|
|
R = PreprocessorOpts.remapped_file_begin(),
|
|
|
|
REnd = PreprocessorOpts.remapped_file_end();
|
|
|
|
!AnyFileChanged && R != REnd;
|
|
|
|
++R) {
|
|
|
|
struct stat StatBuf;
|
2011-03-19 03:23:38 +08:00
|
|
|
if (FileMgr->getNoncachedStatValue(R->second, StatBuf)) {
|
2010-07-31 08:40:00 +08:00
|
|
|
// If we can't stat the file we're remapping to, assume that something
|
|
|
|
// horrible happened.
|
|
|
|
AnyFileChanged = true;
|
|
|
|
break;
|
|
|
|
}
|
2010-07-24 08:38:13 +08:00
|
|
|
|
2010-07-31 08:40:00 +08:00
|
|
|
OverriddenFiles[R->first] = std::make_pair(StatBuf.st_size,
|
|
|
|
StatBuf.st_mtime);
|
|
|
|
}
|
|
|
|
for (PreprocessorOptions::remapped_file_buffer_iterator
|
|
|
|
R = PreprocessorOpts.remapped_file_buffer_begin(),
|
|
|
|
REnd = PreprocessorOpts.remapped_file_buffer_end();
|
|
|
|
!AnyFileChanged && R != REnd;
|
|
|
|
++R) {
|
|
|
|
// FIXME: Should we actually compare the contents of file->buffer
|
|
|
|
// remappings?
|
|
|
|
OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(),
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether anything has changed.
|
|
|
|
for (llvm::StringMap<std::pair<off_t, time_t> >::iterator
|
|
|
|
F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end();
|
|
|
|
!AnyFileChanged && F != FEnd;
|
|
|
|
++F) {
|
|
|
|
llvm::StringMap<std::pair<off_t, time_t> >::iterator Overridden
|
|
|
|
= OverriddenFiles.find(F->first());
|
|
|
|
if (Overridden != OverriddenFiles.end()) {
|
|
|
|
// This file was remapped; check whether the newly-mapped file
|
|
|
|
// matches up with the previous mapping.
|
|
|
|
if (Overridden->second != F->second)
|
|
|
|
AnyFileChanged = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The file was not remapped; check whether it has changed on disk.
|
|
|
|
struct stat StatBuf;
|
2011-03-19 03:23:38 +08:00
|
|
|
if (FileMgr->getNoncachedStatValue(F->first(), StatBuf)) {
|
2010-07-31 08:40:00 +08:00
|
|
|
// If we can't stat the file, assume that something horrible happened.
|
|
|
|
AnyFileChanged = true;
|
|
|
|
} else if (StatBuf.st_size != F->second.first ||
|
|
|
|
StatBuf.st_mtime != F->second.second)
|
|
|
|
AnyFileChanged = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!AnyFileChanged) {
|
2010-08-03 04:51:39 +08:00
|
|
|
// Okay! We can re-use the precompiled preamble.
|
|
|
|
|
|
|
|
// Set the state of the diagnostic object to mimic its state
|
|
|
|
// after parsing the preamble.
|
|
|
|
getDiagnostics().Reset();
|
2010-10-12 05:37:58 +08:00
|
|
|
ProcessWarningOptions(getDiagnostics(),
|
2011-07-02 02:22:13 +08:00
|
|
|
PreambleInvocation->getDiagnosticOpts());
|
2010-08-03 04:51:39 +08:00
|
|
|
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
|
|
|
|
|
|
|
|
// Create a version of the main file buffer that is padded to
|
|
|
|
// buffer size we reserved when creating the preamble.
|
2010-07-31 08:40:00 +08:00
|
|
|
return CreatePaddedMainFileBuffer(NewPreamble.first,
|
|
|
|
PreambleReservedSize,
|
2012-01-21 00:28:04 +08:00
|
|
|
FrontendOpts.Inputs[0].File);
|
2010-07-31 08:40:00 +08:00
|
|
|
}
|
2010-07-24 07:58:40 +08:00
|
|
|
}
|
2010-08-10 04:45:32 +08:00
|
|
|
|
|
|
|
// If we aren't allowed to rebuild the precompiled preamble, just
|
|
|
|
// return now.
|
|
|
|
if (!AllowRebuild)
|
|
|
|
return 0;
|
2010-10-08 12:03:57 +08:00
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// We can't reuse the previously-computed preamble. Build a new one.
|
|
|
|
Preamble.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
|
|
|
PreambleDiagnostics.clear();
|
2011-10-28 01:55:18 +08:00
|
|
|
erasePreambleFile(this);
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = 1;
|
2010-08-10 04:45:32 +08:00
|
|
|
} else if (!AllowRebuild) {
|
|
|
|
// We aren't allowed to rebuild the precompiled preamble; just
|
|
|
|
// return now.
|
|
|
|
return 0;
|
|
|
|
}
|
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;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-09-12 01:56:52 +08:00
|
|
|
// Create a temporary file for the precompiled preamble. In rare
|
|
|
|
// circumstances, this can fail.
|
|
|
|
std::string PreamblePCHPath = GetPreamblePCHPath();
|
|
|
|
if (PreamblePCHPath.empty()) {
|
|
|
|
// Try again next time.
|
|
|
|
PreambleRebuildCounter = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// We did not previously compute a preamble, or it can't be reused anyway.
|
2010-10-28 23:44:59 +08:00
|
|
|
SimpleTimer PreambleTimer(WantTiming);
|
2010-11-10 04:00:56 +08:00
|
|
|
PreambleTimer.setOutput("Precompiling preamble");
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create a new buffer that stores the preamble. The buffer also contains
|
|
|
|
// extra space for the original contents of the file (which will be present
|
|
|
|
// when we actually parse the file) along with more room in case the file
|
2010-07-24 07:58:40 +08:00
|
|
|
// grows.
|
|
|
|
PreambleReservedSize = NewPreamble.first->getBufferSize();
|
|
|
|
if (PreambleReservedSize < 4096)
|
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
|
|
|
PreambleReservedSize = 8191;
|
2010-07-23 08:33:23 +08:00
|
|
|
else
|
2010-07-24 07:58:40 +08:00
|
|
|
PreambleReservedSize *= 2;
|
|
|
|
|
2010-08-03 04:51:39 +08:00
|
|
|
// Save the preamble text for later; we'll need to compare against it for
|
|
|
|
// subsequent reparses.
|
2012-01-21 00:28:04 +08:00
|
|
|
StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].File;
|
2011-09-20 04:40:35 +08:00
|
|
|
Preamble.assign(FileMgr->getFile(MainFilename),
|
|
|
|
NewPreamble.first->getBufferStart(),
|
2010-08-03 04:51:39 +08:00
|
|
|
NewPreamble.first->getBufferStart()
|
|
|
|
+ NewPreamble.second.first);
|
|
|
|
PreambleEndsAtStartOfLine = NewPreamble.second.second;
|
|
|
|
|
2010-08-19 09:33:06 +08:00
|
|
|
delete PreambleBuffer;
|
|
|
|
PreambleBuffer
|
2010-07-24 07:58:40 +08:00
|
|
|
= llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize,
|
2012-01-21 00:28:04 +08:00
|
|
|
FrontendOpts.Inputs[0].File);
|
2010-07-23 08:33:23 +08:00
|
|
|
memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()),
|
2010-07-24 07:58:40 +08:00
|
|
|
NewPreamble.first->getBufferStart(), Preamble.size());
|
|
|
|
memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(),
|
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
|
|
|
' ', PreambleReservedSize - Preamble.size() - 1);
|
|
|
|
const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n';
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Remap the main source file to the preamble buffer.
|
2012-01-21 00:28:04 +08:00
|
|
|
llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File);
|
2010-07-23 08:33:23 +08:00
|
|
|
PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer);
|
|
|
|
|
|
|
|
// Tell the compiler invocation to generate a temporary precompiled header.
|
|
|
|
FrontendOpts.ProgramAction = frontend::GeneratePCH;
|
|
|
|
// FIXME: Generate the precompiled header into memory?
|
2010-09-12 01:56:52 +08:00
|
|
|
FrontendOpts.OutputFile = PreamblePCHPath;
|
2010-10-08 12:03:57 +08:00
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create the compiler instance to use for building the precompiled preamble.
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
|
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
|
|
|
|
2011-07-02 02:22:13 +08:00
|
|
|
Clang->setInvocation(&*PreambleInvocation);
|
2012-01-21 00:28:04 +08:00
|
|
|
OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Set up diagnostics, capturing all of the diagnostics produced.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setDiagnostics(&getDiagnostics());
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create the target instance.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
|
2012-10-17 07:40:58 +08:00
|
|
|
Clang->getTargetOpts()));
|
2011-03-22 02:40:07 +08:00
|
|
|
if (!Clang->hasTarget()) {
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
|
|
|
|
Preamble.clear();
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
|
2010-08-19 09:33:06 +08:00
|
|
|
PreprocessorOpts.eraseRemappedFile(
|
|
|
|
PreprocessorOpts.remapped_file_buffer_end() - 1);
|
2010-07-24 08:38:13 +08:00
|
|
|
return 0;
|
2010-07-23 08:33:23 +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.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2011-03-22 02:40:07 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
|
2010-07-23 08:33:23 +08:00
|
|
|
"Invocation must have exactly one source file!");
|
2012-01-21 00:28:04 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
|
2010-07-23 08:33:23 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2012-01-21 00:28:04 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
|
2010-07-23 08:33:23 +08:00
|
|
|
"IR inputs not support here!");
|
|
|
|
|
|
|
|
// Clear out old caches and data.
|
2010-10-08 12:03:57 +08:00
|
|
|
getDiagnostics().Reset();
|
2011-03-22 02:40:07 +08:00
|
|
|
ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts());
|
2012-02-02 03:54:02 +08:00
|
|
|
checkAndRemoveNonDriverDiags(StoredDiagnostics);
|
2010-08-04 03:06:41 +08:00
|
|
|
TopLevelDecls.clear();
|
|
|
|
TopLevelDeclsInPreamble.clear();
|
2010-07-23 08:33:23 +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(new FileManager(Clang->getFileSystemOpts()));
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create the source manager.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setSourceManager(new SourceManager(getDiagnostics(),
|
2011-03-22 02:40:17 +08:00
|
|
|
Clang->getFileManager()));
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<PrecompilePreambleAction> Act;
|
2010-08-03 16:14:03 +08:00
|
|
|
Act.reset(new PrecompilePreambleAction(*this));
|
2012-01-21 00:28:04 +08:00
|
|
|
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
|
|
|
|
Preamble.clear();
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
|
2010-08-19 09:33:06 +08:00
|
|
|
PreprocessorOpts.eraseRemappedFile(
|
|
|
|
PreprocessorOpts.remapped_file_buffer_end() - 1);
|
2010-07-24 08:38:13 +08:00
|
|
|
return 0;
|
2010-07-23 08:33:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Act->Execute();
|
|
|
|
Act->EndSourceFile();
|
2011-03-22 02:40:17 +08:00
|
|
|
|
2010-08-04 03:06:41 +08:00
|
|
|
if (Diagnostics->hasErrorOccurred()) {
|
2010-07-24 07:58:40 +08:00
|
|
|
// There were errors parsing the preamble, so no precompiled header was
|
|
|
|
// generated. Forget that we even tried.
|
2010-09-28 00:43:25 +08:00
|
|
|
// FIXME: Should we leave a note for ourselves to try again?
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
|
|
|
|
Preamble.clear();
|
2010-08-04 03:06:41 +08:00
|
|
|
TopLevelDeclsInPreamble.clear();
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
|
2010-08-19 09:33:06 +08:00
|
|
|
PreprocessorOpts.eraseRemappedFile(
|
|
|
|
PreprocessorOpts.remapped_file_buffer_end() - 1);
|
2010-07-24 08:38:13 +08:00
|
|
|
return 0;
|
2010-07-24 07:58:40 +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
|
|
|
// Transfer any diagnostics generated when parsing the preamble into the set
|
|
|
|
// of preamble diagnostics.
|
|
|
|
PreambleDiagnostics.clear();
|
|
|
|
PreambleDiagnostics.insert(PreambleDiagnostics.end(),
|
2011-10-25 01:25:20 +08:00
|
|
|
stored_diag_afterDriver_begin(), stored_diag_end());
|
2012-02-02 03:54:02 +08:00
|
|
|
checkAndRemoveNonDriverDiags(StoredDiagnostics);
|
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
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// Keep track of the preamble we precompiled.
|
2011-10-28 01:55:18 +08:00
|
|
|
setPreambleFile(this, FrontendOpts.OutputFile);
|
2010-08-03 04:51:39 +08:00
|
|
|
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
|
2010-07-31 08:40:00 +08:00
|
|
|
|
|
|
|
// Keep track of all of the files that the source manager knows about,
|
|
|
|
// so we can verify whether they have changed or not.
|
|
|
|
FilesInPreamble.clear();
|
2011-03-22 02:40:07 +08:00
|
|
|
SourceManager &SourceMgr = Clang->getSourceManager();
|
2010-07-31 08:40:00 +08:00
|
|
|
const llvm::MemoryBuffer *MainFileBuffer
|
|
|
|
= SourceMgr.getBuffer(SourceMgr.getMainFileID());
|
|
|
|
for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(),
|
|
|
|
FEnd = SourceMgr.fileinfo_end();
|
|
|
|
F != FEnd;
|
|
|
|
++F) {
|
2011-03-05 09:03:53 +08:00
|
|
|
const FileEntry *File = F->second->OrigEntry;
|
2010-07-31 08:40:00 +08:00
|
|
|
if (!File || F->second->getRawBuffer() == MainFileBuffer)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
FilesInPreamble[File->getName()]
|
|
|
|
= std::make_pair(F->second->getSize(), File->getModificationTime());
|
|
|
|
}
|
|
|
|
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = 1;
|
2010-08-19 09:33:06 +08:00
|
|
|
PreprocessorOpts.eraseRemappedFile(
|
|
|
|
PreprocessorOpts.remapped_file_buffer_end() - 1);
|
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;
|
|
|
|
}
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
return CreatePaddedMainFileBuffer(NewPreamble.first,
|
|
|
|
PreambleReservedSize,
|
2012-01-21 00:28:04 +08:00
|
|
|
FrontendOpts.Inputs[0].File);
|
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() {
|
|
|
|
std::vector<Decl *> Resolved;
|
|
|
|
Resolved.reserve(TopLevelDeclsInPreamble.size());
|
|
|
|
ExternalASTSource &Source = *getASTContext().getExternalSource();
|
|
|
|
for (unsigned I = 0, N = TopLevelDeclsInPreamble.size(); I != N; ++I) {
|
|
|
|
// Resolve the declaration ID to an actual declaration, possibly
|
|
|
|
// deserializing the declaration in the process.
|
|
|
|
Decl *D = Source.GetExternalDecl(TopLevelDeclsInPreamble[I]);
|
|
|
|
if (D)
|
|
|
|
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) {
|
|
|
|
// Steal the created target, context, and preprocessor.
|
|
|
|
TheSema.reset(CI.takeSema());
|
|
|
|
Consumer.reset(CI.takeASTConsumer());
|
|
|
|
Ctx = &CI.getASTContext();
|
|
|
|
PP = &CI.getPreprocessor();
|
|
|
|
CI.setSourceManager(0);
|
|
|
|
CI.setFileManager(0);
|
|
|
|
Target = &CI.getTarget();
|
|
|
|
Reader = CI.getModuleManager();
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef ASTUnit::getMainFileName() const {
|
2012-01-21 00:28:04 +08:00
|
|
|
return Invocation->getFrontendOpts().Inputs[0].File;
|
2010-10-28 23:44:59 +08:00
|
|
|
}
|
|
|
|
|
2011-03-10 01:21:42 +08:00
|
|
|
ASTUnit *ASTUnit::create(CompilerInvocation *CI,
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
2012-07-12 04:59:04 +08:00
|
|
|
bool CaptureDiagnostics,
|
|
|
|
bool UserFilesAreVolatile) {
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<ASTUnit> AST;
|
2011-03-10 01:21:42 +08:00
|
|
|
AST.reset(new ASTUnit(false));
|
2011-11-28 12:55:55 +08:00
|
|
|
ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
|
2011-03-10 01:21:42 +08:00
|
|
|
AST->Diagnostics = Diags;
|
2011-03-22 02:40:17 +08:00
|
|
|
AST->Invocation = CI;
|
2011-03-19 02:22:40 +08:00
|
|
|
AST->FileSystemOpts = CI->getFileSystemOpts();
|
2011-03-22 02:40:17 +08:00
|
|
|
AST->FileMgr = new FileManager(AST->FileSystemOpts);
|
2012-07-12 04:59:04 +08:00
|
|
|
AST->UserFilesAreVolatile = UserFilesAreVolatile;
|
|
|
|
AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
|
|
|
|
UserFilesAreVolatile);
|
2011-03-10 01:21:42 +08:00
|
|
|
|
|
|
|
return AST.take();
|
|
|
|
}
|
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
2011-10-15 05:22:05 +08:00
|
|
|
ASTFrontendAction *Action,
|
2011-11-28 12:56:00 +08:00
|
|
|
ASTUnit *Unit,
|
|
|
|
bool Persistent,
|
|
|
|
StringRef ResourceFilesPath,
|
|
|
|
bool OnlyLocalDecls,
|
|
|
|
bool CaptureDiagnostics,
|
|
|
|
bool PrecompilePreamble,
|
2012-04-11 10:11:16 +08:00
|
|
|
bool CacheCodeCompletionResults,
|
2012-07-03 01:35:10 +08:00
|
|
|
bool IncludeBriefCommentsInCodeCompletion,
|
2012-07-12 04:59:04 +08:00
|
|
|
bool UserFilesAreVolatile,
|
2012-04-11 10:11:16 +08:00
|
|
|
OwningPtr<ASTUnit> *ErrAST) {
|
2011-05-04 07:26:34 +08:00
|
|
|
assert(CI && "A CompilerInvocation is required");
|
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<ASTUnit> OwnAST;
|
2011-10-15 05:22:05 +08:00
|
|
|
ASTUnit *AST = Unit;
|
|
|
|
if (!AST) {
|
|
|
|
// Create the AST unit.
|
2012-07-12 04:59:04 +08:00
|
|
|
OwnAST.reset(create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile));
|
2011-10-15 05:22:05 +08:00
|
|
|
AST = OwnAST.get();
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
if (PrecompilePreamble)
|
|
|
|
AST->PreambleRebuildCounter = 2;
|
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> >
|
2011-05-04 07:26:34 +08:00
|
|
|
DiagCleanup(Diags.getPtr());
|
|
|
|
|
|
|
|
// 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.
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
|
2011-05-04 07:26:34 +08:00
|
|
|
|
|
|
|
// Recover resources if we crash before exiting this method.
|
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
|
|
|
|
CICleanup(Clang.get());
|
|
|
|
|
|
|
|
Clang->setInvocation(CI);
|
2012-01-21 00:28:04 +08:00
|
|
|
AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
|
2011-05-04 07:26:34 +08:00
|
|
|
|
|
|
|
// Set up diagnostics, capturing any diagnostics that would
|
|
|
|
// otherwise be dropped.
|
|
|
|
Clang->setDiagnostics(&AST->getDiagnostics());
|
|
|
|
|
|
|
|
// Create the target instance.
|
|
|
|
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
|
|
|
|
Clang->getTargetOpts()));
|
|
|
|
if (!Clang->hasTarget())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
|
|
|
|
|
|
|
|
assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
|
|
|
|
"Invocation must have exactly one source file!");
|
2012-01-21 00:28:04 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
|
2011-05-04 07:26:34 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2012-01-21 00:28:04 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
|
2011-05-04 07:26:34 +08:00
|
|
|
"IR inputs not supported here!");
|
|
|
|
|
|
|
|
// Configure the various subsystems.
|
|
|
|
AST->TheSema.reset();
|
|
|
|
AST->Ctx = 0;
|
|
|
|
AST->PP = 0;
|
2011-11-02 01:14:15 +08:00
|
|
|
AST->Reader = 0;
|
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());
|
|
|
|
|
|
|
|
// Create the source manager.
|
|
|
|
Clang->setSourceManager(&AST->getSourceManager());
|
|
|
|
|
|
|
|
ASTFrontendAction *Act = Action;
|
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<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);
|
|
|
|
|
2011-05-04 07:26:34 +08:00
|
|
|
return 0;
|
2012-04-11 10:11:16 +08:00
|
|
|
}
|
2011-11-28 12:56:00 +08:00
|
|
|
|
|
|
|
if (Persistent && !TrackerAct) {
|
|
|
|
Clang->getPreprocessor().addPPCallbacks(
|
|
|
|
new MacroDefinitionTrackerPPCallbacks(AST->getCurrentTopLevelHashValue()));
|
|
|
|
std::vector<ASTConsumer*> Consumers;
|
|
|
|
if (Clang->hasASTConsumer())
|
|
|
|
Consumers.push_back(Clang->takeASTConsumer());
|
|
|
|
Consumers.push_back(new TopLevelDeclTrackerConsumer(*AST,
|
|
|
|
AST->getCurrentTopLevelHashValue()));
|
|
|
|
Clang->setASTConsumer(new MultiplexConsumer(Consumers));
|
|
|
|
}
|
2012-06-08 13:48:06 +08:00
|
|
|
if (!Act->Execute()) {
|
|
|
|
AST->transferASTDataFromCompilerInstance(*Clang);
|
|
|
|
if (OwnAST && ErrAST)
|
|
|
|
ErrAST->swap(OwnAST);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
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);
|
2011-05-04 07:26:34 +08:00
|
|
|
|
|
|
|
Act->EndSourceFile();
|
|
|
|
|
2011-10-15 05:22:05 +08:00
|
|
|
if (OwnAST)
|
|
|
|
return OwnAST.take();
|
|
|
|
else
|
|
|
|
return AST;
|
2011-05-04 07:26:34 +08:00
|
|
|
}
|
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
|
|
|
|
if (!Invocation)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// We'll manage file buffers ourselves.
|
|
|
|
Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
|
|
|
|
Invocation->getFrontendOpts().DisableFree = false;
|
2011-01-19 09:02:47 +08:00
|
|
|
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
|
2010-10-12 08:50:20 +08:00
|
|
|
|
|
|
|
llvm::MemoryBuffer *OverrideMainBuffer = 0;
|
2010-10-28 01:24:53 +08:00
|
|
|
if (PrecompilePreamble) {
|
2010-11-16 07:00:34 +08:00
|
|
|
PreambleRebuildCounter = 2;
|
2010-10-12 08:50:20 +08:00
|
|
|
OverrideMainBuffer
|
|
|
|
= getMainBufferWithPrecompiledPreamble(*Invocation);
|
|
|
|
}
|
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
SimpleTimer ParsingTimer(WantTiming);
|
2010-11-10 04:00:56 +08:00
|
|
|
ParsingTimer.setOutput("Parsing " + getMainFileName());
|
2010-10-12 08:50:20 +08:00
|
|
|
|
2011-03-22 09:15:24 +08:00
|
|
|
// Recover resources if we crash before exiting this method.
|
|
|
|
llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer>
|
|
|
|
MemBufferCleanup(OverrideMainBuffer);
|
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
return Parse(OverrideMainBuffer);
|
2010-10-12 08:50:20 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
2010-07-20 05:46:24 +08:00
|
|
|
bool OnlyLocalDecls,
|
2010-07-23 08:33:23 +08:00
|
|
|
bool CaptureDiagnostics,
|
2010-08-10 04:45:32 +08:00
|
|
|
bool PrecompilePreamble,
|
2011-08-26 06:30:56 +08:00
|
|
|
TranslationUnitKind TUKind,
|
2012-07-03 01:35:10 +08:00
|
|
|
bool CacheCodeCompletionResults,
|
2012-07-12 04:59:04 +08:00
|
|
|
bool IncludeBriefCommentsInCodeCompletion,
|
|
|
|
bool UserFilesAreVolatile) {
|
2010-07-20 05:46:24 +08:00
|
|
|
// Create the AST unit.
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<ASTUnit> AST;
|
2010-07-20 05:46:24 +08:00
|
|
|
AST.reset(new ASTUnit(false));
|
2011-01-19 09:02:47 +08:00
|
|
|
ConfigureDiags(Diags, 0, 0, *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;
|
2011-03-22 02:40:17 +08:00
|
|
|
AST->Invocation = CI;
|
2012-07-12 04:59:04 +08:00
|
|
|
AST->UserFilesAreVolatile = UserFilesAreVolatile;
|
2010-07-31 04:58:08 +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> >
|
2011-03-22 09:15:24 +08:00
|
|
|
DiagCleanup(Diags.getPtr());
|
2011-03-18 10:06:56 +08:00
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take();
|
2009-12-01 17:51:01 +08:00
|
|
|
}
|
2009-12-02 11:23:45 +08:00
|
|
|
|
|
|
|
ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
|
|
|
|
const char **ArgEnd,
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef ResourceFilesPath,
|
2009-12-02 11:23:45 +08:00
|
|
|
bool OnlyLocalDecls,
|
2010-11-11 08:39:14 +08:00
|
|
|
bool CaptureDiagnostics,
|
2010-01-23 08:14:00 +08:00
|
|
|
RemappedFile *RemappedFiles,
|
2010-02-19 02:08:43 +08:00
|
|
|
unsigned NumRemappedFiles,
|
2011-03-09 07:35:24 +08:00
|
|
|
bool RemappedFilesKeepOriginalName,
|
2010-08-10 04:45:32 +08:00
|
|
|
bool PrecompilePreamble,
|
2011-08-26 06:30:56 +08:00
|
|
|
TranslationUnitKind TUKind,
|
2012-03-07 09:51:17 +08:00
|
|
|
bool CacheCodeCompletionResults,
|
2012-07-03 01:35:10 +08:00
|
|
|
bool IncludeBriefCommentsInCodeCompletion,
|
2012-04-11 10:11:16 +08:00
|
|
|
bool AllowPCHWithCompilerErrors,
|
2012-04-12 18:11:59 +08:00
|
|
|
bool SkipFunctionBodies,
|
2012-07-12 04:59:04 +08:00
|
|
|
bool UserFilesAreVolatile,
|
2012-10-12 00:05:00 +08:00
|
|
|
bool ForSerialization,
|
2012-04-11 10:11:16 +08:00
|
|
|
OwningPtr<ASTUnit> *ErrAST) {
|
2010-04-06 07:52:57 +08:00
|
|
|
if (!Diags.getPtr()) {
|
2010-04-06 05:10:19 +08:00
|
|
|
// No diagnostics engine was provided, so create our own diagnostics object
|
|
|
|
// with the default options.
|
|
|
|
DiagnosticOptions DiagOpts;
|
2011-01-19 09:02:47 +08:00
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin,
|
|
|
|
ArgBegin);
|
2010-04-06 05:10:19 +08:00
|
|
|
}
|
2009-12-02 11:23:45 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
|
2010-10-12 08:50:20 +08:00
|
|
|
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<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
|
|
|
|
2010-11-11 08:39:14 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
|
2010-10-12 08:50:20 +08:00
|
|
|
StoredDiagnostics);
|
|
|
|
|
2011-04-05 07:11:45 +08:00
|
|
|
CI = clang::createInvocationFromCommandLine(
|
2011-07-18 20:00:32 +08:00
|
|
|
llvm::makeArrayRef(ArgBegin, ArgEnd),
|
|
|
|
Diags);
|
2011-04-05 05:38:51 +08:00
|
|
|
if (!CI)
|
2011-03-08 06:45:01 +08:00
|
|
|
return 0;
|
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
|
2011-03-05 09:03:53 +08:00
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
|
|
|
|
FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
|
|
|
|
if (const llvm::MemoryBuffer *
|
|
|
|
memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
|
|
|
|
CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, memBuf);
|
|
|
|
} else {
|
|
|
|
const char *fname = fileOrBuf.get<const char *>();
|
|
|
|
CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, fname);
|
|
|
|
}
|
|
|
|
}
|
2012-03-07 09:51:17 +08:00
|
|
|
PreprocessorOptions &PPOpts = CI->getPreprocessorOpts();
|
|
|
|
PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
|
|
|
|
PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
|
2010-01-23 08:14:00 +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;
|
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
// Create the AST unit.
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<ASTUnit> AST;
|
2010-10-12 08:50:20 +08:00
|
|
|
AST.reset(new ASTUnit(false));
|
2011-01-19 09:02:47 +08:00
|
|
|
ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics);
|
2010-10-12 08:50:20 +08:00
|
|
|
AST->Diagnostics = Diags;
|
2011-11-18 07:01:17 +08:00
|
|
|
Diags = 0; // Zero out now to ease cleanup during crash recovery.
|
2011-03-19 02:22:40 +08:00
|
|
|
AST->FileSystemOpts = CI->getFileSystemOpts();
|
2011-03-22 02:40:17 +08:00
|
|
|
AST->FileMgr = new FileManager(AST->FileSystemOpts);
|
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)
|
|
|
|
AST->WriterData.reset(new ASTWriterData());
|
2011-11-18 07:01:17 +08:00
|
|
|
CI = 0; // Zero out now to ease cleanup during crash recovery.
|
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
|
|
|
|
2012-04-11 10:11:16 +08:00
|
|
|
if (AST->LoadFromCompilerInvocation(PrecompilePreamble)) {
|
|
|
|
// Some error occurred, if caller wants to examine diagnostics, pass it the
|
|
|
|
// ASTUnit.
|
|
|
|
if (ErrAST) {
|
|
|
|
AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics);
|
|
|
|
ErrAST->swap(AST);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return AST.take();
|
2009-12-02 11:23:45 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
|
|
|
bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
|
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
|
|
|
|
|
|
|
clearFileLevelDecls();
|
2010-07-20 05:46:24 +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();
|
2011-02-06 03:42:43 +08:00
|
|
|
PPOpts.DisableStatCache = true;
|
2010-08-20 08:02:33 +08:00
|
|
|
for (PreprocessorOptions::remapped_file_buffer_iterator
|
|
|
|
R = PPOpts.remapped_file_buffer_begin(),
|
|
|
|
REnd = PPOpts.remapped_file_buffer_end();
|
|
|
|
R != REnd;
|
|
|
|
++R) {
|
|
|
|
delete R->second;
|
|
|
|
}
|
2010-07-31 08:40:00 +08:00
|
|
|
Invocation->getPreprocessorOpts().clearRemappedFiles();
|
2011-03-05 09:03:53 +08:00
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
|
|
|
|
FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
|
|
|
|
if (const llvm::MemoryBuffer *
|
|
|
|
memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
|
|
|
|
Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
|
|
|
|
memBuf);
|
|
|
|
} else {
|
|
|
|
const char *fname = fileOrBuf.get<const char *>();
|
|
|
|
Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
|
|
|
|
fname);
|
|
|
|
}
|
|
|
|
}
|
2010-07-31 08:40:00 +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.
|
2010-07-24 08:38:13 +08:00
|
|
|
llvm::MemoryBuffer *OverrideMainBuffer = 0;
|
2011-10-28 01:55:18 +08:00
|
|
|
if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0)
|
2010-08-20 08:59:43 +08:00
|
|
|
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation);
|
2010-07-24 07:58:40 +08:00
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
// Clear out the diagnostics state.
|
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
|
2011-02-17 02:16:54 +08:00
|
|
|
bool Result = Parse(OverrideMainBuffer);
|
2011-11-01 05:25:31 +08:00
|
|
|
|
|
|
|
// If we're caching global code-completion results, and the top-level
|
|
|
|
// 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();
|
2011-08-05 04:04:59 +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
|
|
|
|
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,
|
|
|
|
/// then passes the result on to
|
|
|
|
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;
|
|
|
|
|
|
|
|
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)
|
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.
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
virtual void ProcessCodeCompleteResults(Sema &S,
|
|
|
|
CodeCompletionContext Context,
|
2010-08-25 14:19:51 +08:00
|
|
|
CodeCompletionResult *Results,
|
2010-08-17 04:01:48 +08:00
|
|
|
unsigned NumResults);
|
2010-08-14 06:48:40 +08:00
|
|
|
|
|
|
|
virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
|
|
|
|
OverloadCandidate *Candidates,
|
|
|
|
unsigned NumCandidates) {
|
|
|
|
Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates);
|
|
|
|
}
|
2011-02-02 03:23:04 +08:00
|
|
|
|
2011-02-02 06:57:45 +08:00
|
|
|
virtual CodeCompletionAllocator &getAllocator() {
|
2011-02-02 03:23:04 +08:00
|
|
|
return Next.getAllocator();
|
|
|
|
}
|
2012-04-11 01:23:48 +08:00
|
|
|
|
|
|
|
virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() {
|
|
|
|
return Next.getCodeCompletionTUInfo();
|
|
|
|
}
|
2010-08-14 06:48:40 +08:00
|
|
|
};
|
|
|
|
}
|
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;
|
|
|
|
|
|
|
|
case CodeCompletionContext::CCC_EnumTag:
|
|
|
|
case CodeCompletionContext::CCC_UnionTag:
|
|
|
|
case CodeCompletionContext::CCC_ClassOrStructTag:
|
|
|
|
OnlyTagNames = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
unsigned IDNS
|
|
|
|
= Results[I].Declaration->getUnderlyingDecl()->getIdentifierNamespace();
|
|
|
|
|
|
|
|
bool Hiding = false;
|
|
|
|
if (OnlyTagNames)
|
|
|
|
Hiding = (IDNS & Decl::IDNS_Tag);
|
|
|
|
else {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Hiding)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
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,
|
2010-08-17 04:01:48 +08:00
|
|
|
unsigned NumResults) {
|
|
|
|
// 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;
|
2010-08-17 04:01:48 +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) {
|
|
|
|
// If the context we are in matches any of the contexts we are
|
|
|
|
// interested in, we'll add this result.
|
|
|
|
if ((C->ShowInContexts & InContexts) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If we haven't added any results previously, do so now.
|
|
|
|
if (!AddedResult) {
|
2010-08-17 05:18:39 +08:00
|
|
|
CalculateHiddenNames(Context, Results, NumResults, S.Context,
|
|
|
|
HiddenNames);
|
2010-08-17 04:01:48 +08:00
|
|
|
AllResults.insert(AllResults.end(), Results, Results + NumResults);
|
|
|
|
AddedResult = true;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
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(),
|
2010-08-25 04:21:13 +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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2010-08-26 21:48:20 +08:00
|
|
|
|
2010-08-17 04:01:48 +08:00
|
|
|
Next.ProcessCodeCompleteResults(S, Context, AllResults.data(),
|
|
|
|
AllResults.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
|
2010-08-05 00:47:14 +08:00
|
|
|
RemappedFile *RemappedFiles,
|
|
|
|
unsigned NumRemappedFiles,
|
2010-08-05 17:09:23 +08:00
|
|
|
bool IncludeMacros,
|
|
|
|
bool IncludeCodePatterns,
|
2012-07-03 01:35:10 +08:00
|
|
|
bool IncludeBriefComments,
|
2010-08-05 00:47:14 +08:00
|
|
|
CodeCompleteConsumer &Consumer,
|
2011-09-26 07:23:43 +08:00
|
|
|
DiagnosticsEngine &Diag, LangOptions &LangOpts,
|
2010-08-05 00:47:14 +08:00
|
|
|
SourceManager &SourceMgr, FileManager &FileMgr,
|
2011-07-23 18:55:15 +08:00
|
|
|
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
|
|
|
|
2012-02-20 22:00:23 +08:00
|
|
|
IntrusiveRefCntPtr<CompilerInvocation>
|
2011-03-22 02:40:17 +08:00
|
|
|
CCInvocation(new CompilerInvocation(*Invocation));
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
|
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
|
|
|
|
2011-03-22 02:40:17 +08:00
|
|
|
Clang->setInvocation(&*CCInvocation);
|
2012-01-21 00:28:04 +08:00
|
|
|
OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File;
|
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);
|
2011-03-22 02:40:17 +08:00
|
|
|
ProcessWarningOptions(Diag, CCInvocation->getDiagnosticOpts());
|
2010-08-05 00:47:14 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(true,
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->getDiagnostics(),
|
2010-08-05 00:47:14 +08:00
|
|
|
StoredDiagnostics);
|
|
|
|
|
|
|
|
// Create the target instance.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
|
|
|
|
Clang->getTargetOpts()));
|
|
|
|
if (!Clang->hasTarget()) {
|
2011-03-22 02:40:17 +08:00
|
|
|
Clang->setInvocation(0);
|
2010-08-19 06:29:43 +08:00
|
|
|
return;
|
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.
|
2011-03-22 02:40:07 +08:00
|
|
|
Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
|
2010-08-05 00:47:14 +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!");
|
2012-01-21 00:28:04 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST &&
|
2010-08-05 00:47:14 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2012-01-21 00:28:04 +08:00
|
|
|
assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR &&
|
2010-08-05 00:47:14 +08:00
|
|
|
"IR inputs not support here!");
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
2010-08-20 08:59:43 +08:00
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
|
2011-03-05 09:03:53 +08:00
|
|
|
FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second;
|
|
|
|
if (const llvm::MemoryBuffer *
|
|
|
|
memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) {
|
|
|
|
PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, memBuf);
|
|
|
|
OwnedBuffers.push_back(memBuf);
|
|
|
|
} else {
|
|
|
|
const char *fname = fileOrBuf.get<const char *>();
|
|
|
|
PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, fname);
|
|
|
|
}
|
2010-08-20 08:59:43 +08:00
|
|
|
}
|
2010-08-05 00:47:14 +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
|
|
|
|
2012-04-12 18:11:59 +08:00
|
|
|
Clang->getFrontendOpts().SkipFunctionBodies = true;
|
|
|
|
|
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.
|
|
|
|
llvm::MemoryBuffer *OverrideMainBuffer = 0;
|
2011-10-28 01:55:18 +08:00
|
|
|
if (!getPreambleFile(this).empty()) {
|
2010-08-10 04:45:32 +08:00
|
|
|
using llvm::sys::FileStatus;
|
|
|
|
llvm::sys::PathWithStatus CompleteFilePath(File);
|
|
|
|
llvm::sys::PathWithStatus MainPath(OriginalSourceFile);
|
|
|
|
if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus())
|
|
|
|
if (const FileStatus *MainStatus = MainPath.getFileStatus())
|
2011-09-04 11:32:04 +08:00
|
|
|
if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID() &&
|
|
|
|
Line > 1)
|
2010-08-20 08:59:43 +08:00
|
|
|
OverrideMainBuffer
|
2011-03-22 02:40:17 +08:00
|
|
|
= getMainBufferWithPrecompiledPreamble(*CCInvocation, false,
|
2010-08-26 02:04:15 +08:00
|
|
|
Line - 1);
|
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.
|
2011-02-06 03:42:43 +08:00
|
|
|
PreprocessorOpts.DisableStatCache = true;
|
2010-10-12 08:50:20 +08:00
|
|
|
StoredDiagnostics.insert(StoredDiagnostics.end(),
|
2011-10-25 01:25:20 +08:00
|
|
|
stored_diag_begin(),
|
|
|
|
stored_diag_afterDriver_begin());
|
2010-08-10 04:45:32 +08:00
|
|
|
if (OverrideMainBuffer) {
|
|
|
|
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.second
|
|
|
|
= PreambleEndsAtStartOfLine;
|
2011-10-28 01:55:18 +08:00
|
|
|
PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this);
|
2010-08-10 04:45:32 +08:00
|
|
|
PreprocessorOpts.DisablePCHValidation = true;
|
|
|
|
|
2010-08-20 08:59:43 +08:00
|
|
|
OwnedBuffers.push_back(OverrideMainBuffer);
|
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
|
|
|
}
|
|
|
|
|
2011-05-07 00:33:08 +08:00
|
|
|
// Disable the preprocessing record
|
|
|
|
PreprocessorOpts.DetailedRecord = false;
|
|
|
|
|
2012-02-05 10:12:40 +08:00
|
|
|
OwningPtr<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])) {
|
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
|
|
|
if (OverrideMainBuffer) {
|
2011-10-28 01:55:18 +08:00
|
|
|
std::string ModName = getPreambleFile(this);
|
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
|
|
|
TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
|
|
|
|
getSourceManager(), PreambleDiagnostics,
|
|
|
|
StoredDiagnostics);
|
|
|
|
}
|
2010-08-05 00:47:14 +08:00
|
|
|
Act->Execute();
|
|
|
|
Act->EndSourceFile();
|
|
|
|
}
|
2012-02-02 03:54:02 +08:00
|
|
|
|
|
|
|
checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
|
2010-08-05 00:47:14 +08:00
|
|
|
}
|
2010-08-13 13:36:37 +08:00
|
|
|
|
2012-09-27 00:39:46 +08:00
|
|
|
bool ASTUnit::Save(StringRef File) {
|
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;
|
|
|
|
if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath,
|
|
|
|
/*makeAbsolute=*/false))
|
2012-09-27 00:39:46 +08:00
|
|
|
return true;
|
2011-07-22 02:44:49 +08:00
|
|
|
|
2010-08-13 13:36:37 +08:00
|
|
|
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
|
|
|
|
// 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
|
|
|
|
2011-12-25 09:18:52 +08:00
|
|
|
if (llvm::sys::fs::rename(TempPath.str(), File)) {
|
2011-07-22 02:44:49 +08:00
|
|
|
bool exists;
|
|
|
|
llvm::sys::fs::remove(TempPath.str(), exists);
|
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) {
|
|
|
|
Writer.WriteAST(S, 0, std::string(), 0, "", hasErrors);
|
|
|
|
|
|
|
|
// 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) {
|
2012-03-07 09:51:17 +08:00
|
|
|
bool hasErrors = getDiagnostics().hasErrorOccurred();
|
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);
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter Writer(Stream);
|
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;
|
|
|
|
|
|
|
|
static void TranslateSLoc(SourceLocation &L, SLocRemap &Remap) {
|
|
|
|
unsigned Raw = L.getRawEncoding();
|
|
|
|
const unsigned MacroBit = 1U << 31;
|
|
|
|
L = SourceLocation::getFromRawEncoding((Raw & MacroBit) |
|
|
|
|
((Raw & ~MacroBit) + Remap.find(Raw & ~MacroBit)->second));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::TranslateStoredDiagnostics(
|
|
|
|
ASTReader *MMan,
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef ModName,
|
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,
|
2011-07-23 18:55:15 +08:00
|
|
|
const SmallVectorImpl<StoredDiagnostic> &Diags,
|
|
|
|
SmallVectorImpl<StoredDiagnostic> &Out) {
|
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
|
|
|
// The stored diagnostic has the old source manager in it; update
|
|
|
|
// the locations to refer 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.
|
|
|
|
// 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());
|
|
|
|
assert(MMan && "Don't have a module manager");
|
2011-12-01 07:21:26 +08:00
|
|
|
serialization::ModuleFile *Mod = MMan->ModuleMgr.lookup(ModName);
|
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
|
|
|
assert(Mod && "Don't have preamble module");
|
|
|
|
SLocRemap &Remap = Mod->SLocRemap;
|
|
|
|
for (unsigned I = 0, N = Diags.size(); I != N; ++I) {
|
|
|
|
// Rebuild the StoredDiagnostic.
|
|
|
|
const StoredDiagnostic &SD = Diags[I];
|
|
|
|
SourceLocation L = SD.getLocation();
|
|
|
|
TranslateSLoc(L, Remap);
|
|
|
|
FullSourceLoc Loc(L, SrcMgr);
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<CharSourceRange, 4> Ranges;
|
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
|
|
|
Ranges.reserve(SD.range_size());
|
|
|
|
for (StoredDiagnostic::range_iterator I = SD.range_begin(),
|
|
|
|
E = SD.range_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
SourceLocation BL = I->getBegin();
|
|
|
|
TranslateSLoc(BL, Remap);
|
|
|
|
SourceLocation EL = I->getEnd();
|
|
|
|
TranslateSLoc(EL, Remap);
|
|
|
|
Ranges.push_back(CharSourceRange(SourceRange(BL, EL), I->isTokenRange()));
|
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<FixItHint, 2> 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.reserve(SD.fixit_size());
|
|
|
|
for (StoredDiagnostic::fixit_iterator I = SD.fixit_begin(),
|
|
|
|
E = SD.fixit_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
FixIts.push_back(FixItHint());
|
|
|
|
FixItHint &FH = FixIts.back();
|
|
|
|
FH.CodeToInsert = I->CodeToInsert;
|
|
|
|
SourceLocation BL = I->RemoveRange.getBegin();
|
|
|
|
TranslateSLoc(BL, Remap);
|
|
|
|
SourceLocation EL = I->RemoveRange.getEnd();
|
|
|
|
TranslateSLoc(EL, Remap);
|
|
|
|
FH.RemoveRange = CharSourceRange(SourceRange(BL, EL),
|
|
|
|
I->RemoveRange.isTokenRange());
|
|
|
|
}
|
|
|
|
|
|
|
|
Result.push_back(StoredDiagnostic(SD.getLevel(), SD.getID(),
|
|
|
|
SD.getMessage(), Loc, Ranges, FixIts));
|
|
|
|
}
|
|
|
|
Result.swap(Out);
|
|
|
|
}
|
2011-09-20 04:40:35 +08:00
|
|
|
|
2011-10-31 15:19:59 +08:00
|
|
|
static inline bool compLocDecl(std::pair<unsigned, Decl *> L,
|
|
|
|
std::pair<unsigned, Decl *> R) {
|
|
|
|
return L.first < R.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::addFileLevelDecl(Decl *D) {
|
|
|
|
assert(D);
|
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;
|
|
|
|
llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
LocDeclsTy::iterator
|
|
|
|
I = std::upper_bound(Decls->begin(), Decls->end(), LocDecl, compLocDecl);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
LocDeclsTy::iterator
|
|
|
|
BeginIt = std::lower_bound(LocDecls.begin(), LocDecls.end(),
|
|
|
|
std::make_pair(Offset, (Decl*)0), compLocDecl);
|
|
|
|
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;
|
|
|
|
|
2011-11-03 10:20:32 +08:00
|
|
|
LocDeclsTy::iterator
|
|
|
|
EndIt = std::upper_bound(LocDecls.begin(), LocDecls.end(),
|
|
|
|
std::make_pair(Offset+Length, (Decl*)0),
|
|
|
|
compLocDecl);
|
|
|
|
if (EndIt != LocDecls.end())
|
|
|
|
++EndIt;
|
|
|
|
|
|
|
|
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.
|
|
|
|
SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) {
|
|
|
|
FileID PreambleID;
|
|
|
|
if (SourceMgr)
|
|
|
|
PreambleID = SourceMgr->getPreambleFileID();
|
|
|
|
|
|
|
|
if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
|
|
|
|
return Loc;
|
|
|
|
|
|
|
|
unsigned Offs;
|
|
|
|
if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) {
|
|
|
|
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.
|
|
|
|
SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) {
|
|
|
|
FileID PreambleID;
|
|
|
|
if (SourceMgr)
|
|
|
|
PreambleID = SourceMgr->getPreambleFileID();
|
|
|
|
|
|
|
|
if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid())
|
|
|
|
return Loc;
|
|
|
|
|
|
|
|
unsigned Offs;
|
|
|
|
if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) &&
|
|
|
|
Offs < Preamble.size()) {
|
|
|
|
SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID);
|
|
|
|
return FileLoc.getLocWithOffset(Offs);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Loc;
|
|
|
|
}
|
|
|
|
|
2011-10-25 08:29:50 +08:00
|
|
|
bool ASTUnit::isInPreambleFileID(SourceLocation Loc) {
|
|
|
|
FileID FID;
|
|
|
|
if (SourceMgr)
|
|
|
|
FID = SourceMgr->getPreambleFileID();
|
|
|
|
|
|
|
|
if (Loc.isInvalid() || FID.isInvalid())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return SourceMgr->isInFileID(Loc, FID);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ASTUnit::isInMainFileID(SourceLocation Loc) {
|
|
|
|
FileID FID;
|
|
|
|
if (SourceMgr)
|
|
|
|
FID = SourceMgr->getMainFileID();
|
|
|
|
|
|
|
|
if (Loc.isInvalid() || FID.isInvalid())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return SourceMgr->isInFileID(Loc, FID);
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation ASTUnit::getEndOfPreambleFileID() {
|
|
|
|
FileID FID;
|
|
|
|
if (SourceMgr)
|
|
|
|
FID = SourceMgr->getPreambleFileID();
|
|
|
|
|
|
|
|
if (FID.isInvalid())
|
|
|
|
return SourceLocation();
|
|
|
|
|
|
|
|
return SourceMgr->getLocForEndOfFile(FID);
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation ASTUnit::getStartOfMainFileID() {
|
|
|
|
FileID FID;
|
|
|
|
if (SourceMgr)
|
|
|
|
FID = SourceMgr->getMainFileID();
|
|
|
|
|
|
|
|
if (FID.isInvalid())
|
|
|
|
return SourceLocation();
|
|
|
|
|
|
|
|
return SourceMgr->getLocForStartOfFile(FID);
|
|
|
|
}
|
|
|
|
|
2012-10-03 00:10:51 +08:00
|
|
|
std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
|
|
|
|
ASTUnit::getLocalPreprocessingEntities() const {
|
|
|
|
if (isMainFileAST()) {
|
|
|
|
serialization::ModuleFile &
|
|
|
|
Mod = Reader->getModuleManager().getPrimaryModule();
|
|
|
|
return Reader->getModulePreprocessedEntities(Mod);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
|
|
|
|
return std::make_pair(PPRec->local_begin(), PPRec->local_end());
|
|
|
|
|
|
|
|
return std::make_pair(PreprocessingRecord::iterator(),
|
|
|
|
PreprocessingRecord::iterator());
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
ASTReader::ModuleDeclIterator MDI, MDE;
|
|
|
|
llvm::tie(MDI, MDE) = Reader->getModuleFileLevelDecls(Mod);
|
|
|
|
for (; MDI != MDE; ++MDI) {
|
|
|
|
if (!Fn(context, *MDI))
|
|
|
|
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
|
|
|
namespace {
|
|
|
|
struct PCHLocatorInfo {
|
|
|
|
serialization::ModuleFile *Mod;
|
|
|
|
PCHLocatorInfo() : Mod(0) {}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool PCHLocator(serialization::ModuleFile &M, void *UserData) {
|
|
|
|
PCHLocatorInfo &Info = *static_cast<PCHLocatorInfo*>(UserData);
|
|
|
|
switch (M.Kind) {
|
|
|
|
case serialization::MK_Module:
|
|
|
|
return true; // skip dependencies.
|
|
|
|
case serialization::MK_PCH:
|
|
|
|
Info.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
const FileEntry *ASTUnit::getPCHFile() {
|
|
|
|
if (!Reader)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
PCHLocatorInfo Info;
|
|
|
|
Reader->getModuleManager().visit(PCHLocator, &Info);
|
|
|
|
if (Info.Mod)
|
|
|
|
return Info.Mod->File;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-10 10:12:47 +08:00
|
|
|
bool ASTUnit::isModuleFile() {
|
|
|
|
return isMainFileAST() && !ASTFileLangOpts.CurrentModule.empty();
|
|
|
|
}
|
|
|
|
|
2011-09-20 04:40:35 +08:00
|
|
|
void ASTUnit::PreambleData::countLines() const {
|
|
|
|
NumLines = 0;
|
|
|
|
if (empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (std::vector<char>::const_iterator
|
|
|
|
I = Buffer.begin(), E = Buffer.end(); I != E; ++I) {
|
|
|
|
if (*I == '\n')
|
|
|
|
++NumLines;
|
|
|
|
}
|
|
|
|
if (Buffer.back() != '\n')
|
|
|
|
++NumLines;
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
ASTUnit::ConcurrencyState::ConcurrencyState() {}
|
|
|
|
ASTUnit::ConcurrencyState::~ConcurrencyState() {}
|
|
|
|
void ASTUnit::ConcurrencyState::start() {}
|
|
|
|
void ASTUnit::ConcurrencyState::finish() {}
|
|
|
|
|
|
|
|
#endif
|