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-02 11:23:45 +08:00
|
|
|
#include "clang/Driver/Compilation.h"
|
|
|
|
#include "clang/Driver/Driver.h"
|
|
|
|
#include "clang/Driver/Job.h"
|
|
|
|
#include "clang/Driver/Tool.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"
|
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-11-30 14:16:57 +08:00
|
|
|
#include "clang/Serialization/ASTSerializationListener.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"
|
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"
|
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
|
|
|
}
|
|
|
|
|
2010-11-10 04:00:56 +08:00
|
|
|
void setOutput(const llvm::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';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
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)
|
2010-07-20 05:46:24 +08:00
|
|
|
: CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
|
2010-10-28 23:44:59 +08:00
|
|
|
CompleteTranslationUnit(true), WantTiming(getenv("LIBCLANG_TIMING")),
|
|
|
|
NumStoredDiagnosticsFromDriver(0),
|
2010-10-12 08:50:20 +08:00
|
|
|
ConcurrencyCheckValue(CheckUnlocked),
|
2010-08-19 09:33:06 +08:00
|
|
|
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
|
2010-08-17 08:40:40 +08:00
|
|
|
ShouldCacheCodeCompletionResults(false),
|
|
|
|
NumTopLevelDeclsAtLastCompletionCache(0),
|
2010-08-19 08:45:44 +08:00
|
|
|
CacheCodeCompletionCoolDown(0),
|
|
|
|
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() {
|
2010-03-06 05:16:25 +08:00
|
|
|
ConcurrencyCheckValue = CheckLocked;
|
2010-07-20 05:46:24 +08:00
|
|
|
CleanTemporaryFiles();
|
2010-07-24 07:58:40 +08:00
|
|
|
if (!PreambleFile.empty())
|
2010-07-31 04:58:08 +08:00
|
|
|
llvm::sys::Path(PreambleFile).eraseFromDisk();
|
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.
|
|
|
|
if (Invocation.get()) {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::CleanTemporaryFiles() {
|
2010-02-19 07:35:40 +08:00
|
|
|
for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
|
|
|
|
TemporaryFiles[I].eraseFromDisk();
|
2010-07-20 05:46:24 +08:00
|
|
|
TemporaryFiles.clear();
|
2009-10-16 06:23:48 +08:00
|
|
|
}
|
2009-06-20 16:08:23 +08:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
unsigned Contexts = 0;
|
|
|
|
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))
|
|
|
|
Contexts |= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Statement - 1))
|
2010-09-15 07:59:36 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_Type - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1));
|
2010-08-15 14:18:01 +08:00
|
|
|
|
|
|
|
// In C++, types can appear in expressions contexts (for functional casts).
|
|
|
|
if (LangOpts.CPlusPlus)
|
|
|
|
Contexts |= (1 << (CodeCompletionContext::CCC_Expression - 1));
|
|
|
|
|
|
|
|
// 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))
|
|
|
|
Contexts |= (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
|
|
|
|
|
|
|
|
// Deal with tag names.
|
|
|
|
if (isa<EnumDecl>(ND)) {
|
|
|
|
Contexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1));
|
|
|
|
|
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())
|
|
|
|
Contexts |= (1 << (CodeCompletionContext::CCC_UnionTag - 1));
|
|
|
|
else
|
|
|
|
Contexts |= (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
|
|
|
|
|
|
|
|
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.
|
|
|
|
Contexts = (1 << (CodeCompletionContext::CCC_Statement - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Expression - 1))
|
2010-09-15 07:59:36 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
|
2010-08-15 14:18:01 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
|
|
|
|
} else if (isa<ObjCProtocolDecl>(ND)) {
|
|
|
|
Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
|
|
|
|
} else if (isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND)) {
|
2010-08-17 07:05:20 +08:00
|
|
|
Contexts = (1 << (CodeCompletionContext::CCC_Namespace - 1));
|
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;
|
2010-08-14 06:48:40 +08:00
|
|
|
llvm::SmallVector<Result, 8> Results;
|
2011-02-02 03:23:04 +08:00
|
|
|
TheSema->GatherGlobalCodeCompletions(CachedCompletionAllocator, 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,
|
|
|
|
CachedCompletionAllocator);
|
2010-08-15 14:18:01 +08:00
|
|
|
CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration,
|
2010-08-17 07:05:20 +08:00
|
|
|
Ctx->getLangOptions(),
|
|
|
|
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++.
|
|
|
|
if (TheSema->Context.getLangOptions().CPlusPlus &&
|
|
|
|
IsNestedNameSpecifier && !Results[I].StartsNestedNameSpecifier) {
|
|
|
|
// The contexts in which a nested-name-specifier can appear in C++.
|
|
|
|
unsigned NNSContexts
|
|
|
|
= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Statement - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Expression - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_EnumTag - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_UnionTag - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1))
|
2010-08-24 02:23:48 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_Type - 1))
|
2010-09-15 07:59:36 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1));
|
2010-08-17 07:05:20 +08:00
|
|
|
|
|
|
|
if (isa<NamespaceDecl>(Results[I].Declaration) ||
|
|
|
|
isa<NamespaceAliasDecl>(Results[I].Declaration))
|
|
|
|
NNSContexts |= (1 << (CodeCompletionContext::CCC_Namespace - 1));
|
|
|
|
|
|
|
|
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,
|
|
|
|
CachedCompletionAllocator);
|
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,
|
|
|
|
CachedCompletionAllocator);
|
2010-08-14 06:48:40 +08:00
|
|
|
CachedResult.ShowInContexts
|
|
|
|
= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCInterface - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Statement - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Expression - 1))
|
2010-08-25 04:21:13 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
|
2010-08-25 06:20:20 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_MacroNameUse - 1))
|
2010-09-15 07:59:36 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1));
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-17 08:40:40 +08:00
|
|
|
// Make a note of the state when we performed this caching.
|
|
|
|
NumTopLevelDeclsAtLastCompletionCache = top_level_size();
|
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-02 03:23:04 +08:00
|
|
|
CachedCompletionAllocator.Reset();
|
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 {
|
2009-06-20 16:08:23 +08:00
|
|
|
LangOptions &LangOpt;
|
|
|
|
HeaderSearch &HSI;
|
|
|
|
std::string &TargetTriple;
|
|
|
|
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
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
public:
|
2010-08-19 07:57:06 +08:00
|
|
|
ASTInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
|
2009-06-20 16:08:23 +08:00
|
|
|
std::string &TargetTriple, std::string &Predefines,
|
|
|
|
unsigned &Counter)
|
|
|
|
: LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple),
|
|
|
|
Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
virtual bool ReadLanguageOptions(const LangOptions &LangOpts) {
|
|
|
|
LangOpt = LangOpts;
|
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-11 08:52:11 +08:00
|
|
|
virtual bool ReadTargetTriple(llvm::StringRef Triple) {
|
2009-06-20 16:08:23 +08:00
|
|
|
TargetTriple = Triple;
|
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-07-15 07:29:55 +08:00
|
|
|
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
2009-11-11 13:29:04 +08:00
|
|
|
llvm::StringRef OriginalFileName,
|
2009-06-20 16:08:23 +08:00
|
|
|
std::string &SuggestedPredefines) {
|
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
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
virtual void ReadCounter(unsigned Value) {
|
|
|
|
Counter = Value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
class StoredDiagnosticClient : public DiagnosticClient {
|
|
|
|
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit StoredDiagnosticClient(
|
|
|
|
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
|
|
|
|
: StoredDiags(StoredDiags) { }
|
|
|
|
|
|
|
|
virtual void HandleDiagnostic(Diagnostic::Level Level,
|
|
|
|
const DiagnosticInfo &Info);
|
|
|
|
};
|
|
|
|
|
|
|
|
/// \brief RAII object that optionally captures diagnostics, if
|
|
|
|
/// there is no diagnostic client to capture them already.
|
|
|
|
class CaptureDroppedDiagnostics {
|
|
|
|
Diagnostic &Diags;
|
|
|
|
StoredDiagnosticClient Client;
|
|
|
|
DiagnosticClient *PreviousClient;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
|
2010-11-11 08:39:14 +08:00
|
|
|
llvm::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
|
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level,
|
|
|
|
const DiagnosticInfo &Info) {
|
2010-11-19 04:06:46 +08:00
|
|
|
// Default implementation (Warnings/errors count).
|
|
|
|
DiagnosticClient::HandleDiagnostic(Level, Info);
|
|
|
|
|
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
|
|
|
|
2010-08-19 07:57:06 +08:00
|
|
|
const std::string &ASTUnit::getASTFileName() {
|
|
|
|
assert(isMainFileAST() && "Not an ASTUnit from an AST file!");
|
2010-08-19 07:56:43 +08:00
|
|
|
return static_cast<ASTReader *>(Ctx->getExternalSource())->getFileName();
|
2009-10-16 06:23:48 +08:00
|
|
|
}
|
|
|
|
|
2010-11-04 06:45:23 +08:00
|
|
|
llvm::MemoryBuffer *ASTUnit::getBufferForFile(llvm::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.
|
|
|
|
void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &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;
|
|
|
|
DiagnosticClient *Client = 0;
|
|
|
|
if (CaptureDiagnostics)
|
|
|
|
Client = new StoredDiagnosticClient(AST.StoredDiagnostics);
|
2011-01-19 09:02:47 +08:00
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd- ArgBegin,
|
|
|
|
ArgBegin, Client);
|
2010-11-11 08:39:14 +08:00
|
|
|
} else if (CaptureDiagnostics) {
|
|
|
|
Diags->setClient(new StoredDiagnosticClient(AST.StoredDiagnostics));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-19 07:57:06 +08:00
|
|
|
ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
|
2010-04-06 07:52:57 +08:00
|
|
|
llvm::IntrusiveRefCntPtr<Diagnostic> 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,
|
|
|
|
bool CaptureDiagnostics) {
|
2010-04-06 05:10:19 +08:00
|
|
|
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
|
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;
|
2010-11-23 15:51:02 +08:00
|
|
|
AST->FileMgr.reset(new FileManager(FileSystemOpts));
|
2010-11-04 06:45:23 +08:00
|
|
|
AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics(),
|
2010-11-23 16:35:12 +08:00
|
|
|
AST->getFileManager()));
|
|
|
|
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
|
2010-08-13 11:15:25 +08:00
|
|
|
|
2010-01-23 08:14:00 +08:00
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
|
|
|
|
// Create the file entry for the file that we're mapping from.
|
|
|
|
const FileEntry *FromFile
|
|
|
|
= AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
|
|
|
|
RemappedFiles[I].second->getBufferSize(),
|
2010-11-23 16:35:12 +08:00
|
|
|
0);
|
2010-01-23 08:14:00 +08:00
|
|
|
if (!FromFile) {
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
|
2010-01-23 08:14:00 +08:00
|
|
|
<< RemappedFiles[I].first;
|
2010-02-27 09:32:48 +08:00
|
|
|
delete RemappedFiles[I].second;
|
2010-01-23 08:14:00 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override the contents of the "from" file with the contents of
|
|
|
|
// the "to" file.
|
|
|
|
AST->getSourceManager().overrideFileContents(FromFile,
|
|
|
|
RemappedFiles[I].second);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
LangOptions LangInfo;
|
|
|
|
HeaderSearch &HeaderInfo = *AST->HeaderInfo.get();
|
|
|
|
std::string TargetTriple;
|
|
|
|
std::string Predefines;
|
|
|
|
unsigned Counter;
|
|
|
|
|
2010-08-19 07:56:43 +08:00
|
|
|
llvm::OwningPtr<ASTReader> Reader;
|
2009-06-20 16:08:23 +08:00
|
|
|
|
2010-08-19 07:56:43 +08:00
|
|
|
Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(),
|
2010-11-23 16:35:12 +08:00
|
|
|
AST->getDiagnostics()));
|
2010-08-19 07:57:06 +08:00
|
|
|
Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple,
|
2009-09-03 13:59:35 +08:00
|
|
|
Predefines, Counter));
|
|
|
|
|
2010-10-06 00:15:19 +08:00
|
|
|
switch (Reader->ReadAST(Filename, ASTReader::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:
|
|
|
|
case ASTReader::IgnorePCH:
|
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();
|
|
|
|
|
2010-08-19 07:57:06 +08:00
|
|
|
// AST file loaded successfully. Now create the preprocessor.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// Get information about the target being compiled for.
|
2009-11-15 14:48:46 +08:00
|
|
|
//
|
2010-08-19 07:57:06 +08:00
|
|
|
// FIXME: This is broken, we should store the TargetOptions in the AST file.
|
2009-11-15 14:48:46 +08:00
|
|
|
TargetOptions TargetOpts;
|
|
|
|
TargetOpts.ABI = "";
|
2010-08-22 14:43:33 +08:00
|
|
|
TargetOpts.CXXABI = "";
|
2009-11-15 14:48:46 +08:00
|
|
|
TargetOpts.CPU = "";
|
|
|
|
TargetOpts.Features.clear();
|
|
|
|
TargetOpts.Triple = TargetTriple;
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
|
|
|
|
TargetOpts));
|
|
|
|
AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo,
|
|
|
|
*AST->Target.get(),
|
2009-09-21 11:03:39 +08:00
|
|
|
AST->getSourceManager(), HeaderInfo));
|
2009-06-20 16:08:23 +08:00
|
|
|
Preprocessor &PP = *AST->PP.get();
|
|
|
|
|
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-03 13:59:35 +08:00
|
|
|
Reader->setPreprocessor(PP);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// Create and initialize the ASTContext.
|
|
|
|
|
|
|
|
AST->Ctx.reset(new ASTContext(LangInfo,
|
2009-09-21 11:03:39 +08:00
|
|
|
AST->getSourceManager(),
|
2009-06-20 16:08:23 +08:00
|
|
|
*AST->Target.get(),
|
|
|
|
PP.getIdentifierTable(),
|
|
|
|
PP.getSelectorTable(),
|
|
|
|
PP.getBuiltinInfo(),
|
|
|
|
/* size_reserve = */0));
|
|
|
|
ASTContext &Context = *AST->Ctx.get();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-03 13:59:35 +08:00
|
|
|
Reader->InitializeContext(Context);
|
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();
|
2010-08-13 11:15:25 +08:00
|
|
|
llvm::OwningPtr<ExternalASTSource> Source(Reader.take());
|
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);
|
|
|
|
|
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 {
|
|
|
|
|
2009-12-04 16:17:33 +08:00
|
|
|
class TopLevelDeclTrackerConsumer : public ASTConsumer {
|
|
|
|
ASTUnit &Unit;
|
|
|
|
|
|
|
|
public:
|
|
|
|
TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
|
|
|
|
|
|
|
|
void HandleTopLevelDecl(DeclGroupRef D) {
|
2010-05-04 04:16:35 +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;
|
2010-08-04 03:06:41 +08:00
|
|
|
Unit.addTopLevelDecl(D);
|
2010-05-04 04:16:35 +08:00
|
|
|
}
|
2009-12-04 16:17:33 +08:00
|
|
|
}
|
2010-08-12 02:52:41 +08:00
|
|
|
|
|
|
|
// We're not interested in "interesting" decls.
|
|
|
|
void HandleInterestingDecl(DeclGroupRef) {}
|
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,
|
|
|
|
llvm::StringRef InFile) {
|
2009-12-04 16:17:33 +08:00
|
|
|
return new TopLevelDeclTrackerConsumer(Unit);
|
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; }
|
2010-08-10 04:45:32 +08:00
|
|
|
virtual bool usesCompleteTranslationUnit() {
|
|
|
|
return Unit.isCompleteTranslationUnit();
|
|
|
|
}
|
2009-12-01 17:51:01 +08:00
|
|
|
};
|
|
|
|
|
2010-11-30 14:16:57 +08:00
|
|
|
class PrecompilePreambleConsumer : public PCHGenerator,
|
|
|
|
public ASTSerializationListener {
|
2010-08-03 16:14:03 +08:00
|
|
|
ASTUnit &Unit;
|
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:
|
|
|
|
PrecompilePreambleConsumer(ASTUnit &Unit,
|
|
|
|
const Preprocessor &PP, bool Chaining,
|
|
|
|
const char *isysroot, llvm::raw_ostream *Out)
|
|
|
|
: PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { }
|
|
|
|
|
2010-08-04 03:06:41 +08:00
|
|
|
virtual void 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;
|
2010-08-04 03:06:41 +08:00
|
|
|
TopLevelDecls.push_back(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
2010-11-30 14:16:57 +08:00
|
|
|
|
|
|
|
virtual void SerializedPreprocessedEntity(PreprocessedEntity *Entity,
|
|
|
|
uint64_t Offset) {
|
|
|
|
Unit.addPreprocessedEntityFromPreamble(Offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ASTSerializationListener *GetASTSerializationListener() {
|
|
|
|
return this;
|
|
|
|
}
|
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,
|
|
|
|
llvm::StringRef InFile) {
|
|
|
|
std::string Sysroot;
|
|
|
|
llvm::raw_ostream *OS = 0;
|
|
|
|
bool Chaining;
|
|
|
|
if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot,
|
|
|
|
OS, Chaining))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
|
|
|
|
Sysroot.c_str() : 0;
|
|
|
|
return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining,
|
|
|
|
isysroot, OS);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool hasCodeCompletionSupport() const { return false; }
|
|
|
|
virtual bool hasASTFileSupport() const { return false; }
|
2010-08-10 04:45:32 +08:00
|
|
|
virtual bool usesCompleteTranslationUnit() { return false; }
|
2010-08-03 16:14:03 +08:00
|
|
|
};
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
}
|
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
/// Parse the source file into a translation unit using the given compiler
|
|
|
|
/// invocation, replacing the current translation unit.
|
|
|
|
///
|
|
|
|
/// \returns True if a failure occurred that causes the ASTUnit not to
|
|
|
|
/// contain any translation-unit information, false otherwise.
|
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;
|
|
|
|
|
2010-08-19 09:33:06 +08:00
|
|
|
if (!Invocation.get()) {
|
|
|
|
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.
|
2009-12-02 16:43:56 +08:00
|
|
|
CompilerInstance Clang;
|
2010-07-20 05:46:24 +08:00
|
|
|
Clang.setInvocation(Invocation.take());
|
|
|
|
OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
|
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Set up diagnostics, capturing any diagnostics that would
|
|
|
|
// otherwise be dropped.
|
2010-07-20 05:46:24 +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-01-28 02:02:58 +08:00
|
|
|
Clang.getTargetOpts().Features = TargetFeatures;
|
2009-12-01 17:51:01 +08:00
|
|
|
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
|
|
|
Clang.getTargetOpts()));
|
2010-08-19 09:33:06 +08:00
|
|
|
if (!Clang.hasTarget()) {
|
|
|
|
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.
|
|
|
|
Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
|
|
|
|
"Invocation must have exactly one source file!");
|
2010-06-08 07:22:09 +08:00
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
|
2009-12-01 17:51:01 +08:00
|
|
|
"FIXME: AST inputs not yet supported here!");
|
2010-06-08 07:26:47 +08:00
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
|
|
|
|
"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?
|
2010-11-04 06:45:23 +08:00
|
|
|
FileSystemOpts = Clang.getFileSystemOpts();
|
2010-11-23 16:35:12 +08:00
|
|
|
FileMgr.reset(new FileManager(Clang.getFileSystemOpts()));
|
|
|
|
SourceMgr.reset(new SourceManager(getDiagnostics(), *FileMgr));
|
2010-08-13 11:15:25 +08:00
|
|
|
TheSema.reset();
|
2010-07-20 05:46:24 +08:00
|
|
|
Ctx.reset();
|
|
|
|
PP.reset();
|
|
|
|
|
|
|
|
// Clear out old caches and data.
|
|
|
|
TopLevelDecls.clear();
|
2010-11-30 14:16:57 +08:00
|
|
|
PreprocessedEntities.clear();
|
2010-07-20 05:46:24 +08:00
|
|
|
CleanTemporaryFiles();
|
|
|
|
PreprocessedEntitiesByFile.clear();
|
2010-08-03 04:51:39 +08:00
|
|
|
|
2010-08-20 08:02:33 +08:00
|
|
|
if (!OverrideMainBuffer) {
|
2010-10-12 08:50:20 +08:00
|
|
|
StoredDiagnostics.erase(
|
|
|
|
StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
|
|
|
|
StoredDiagnostics.end());
|
2010-08-20 08:02:33 +08:00
|
|
|
TopLevelDeclsInPreamble.clear();
|
2010-11-30 14:16:57 +08:00
|
|
|
PreprocessedEntitiesInPreamble.clear();
|
2010-08-20 08:02:33 +08:00
|
|
|
}
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create a file manager object to provide access to and cache the filesystem.
|
2010-07-20 05:46:24 +08:00
|
|
|
Clang.setFileManager(&getFileManager());
|
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the source manager.
|
2010-07-20 05:46:24 +08:00
|
|
|
Clang.setSourceManager(&getSourceManager());
|
|
|
|
|
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.
|
|
|
|
PreprocessorOptions &PreprocessorOpts = Clang.getPreprocessorOpts();
|
2010-08-05 00:47:14 +08:00
|
|
|
std::string PriorImplicitPCHInclude;
|
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;
|
2010-08-05 00:47:14 +08:00
|
|
|
PriorImplicitPCHInclude = PreprocessorOpts.ImplicitPCHInclude;
|
2010-07-31 04:58:08 +08:00
|
|
|
PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
|
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.
|
2010-10-12 08:50:20 +08:00
|
|
|
for (unsigned I = NumStoredDiagnosticsFromDriver,
|
|
|
|
N = StoredDiagnostics.size();
|
|
|
|
I < N; ++I) {
|
2010-08-03 04:51:39 +08:00
|
|
|
FullSourceLoc Loc(StoredDiagnostics[I].getLocation(),
|
|
|
|
getSourceManager());
|
|
|
|
StoredDiagnostics[I].setLocation(Loc);
|
|
|
|
}
|
2010-10-12 08:50:20 +08:00
|
|
|
|
|
|
|
// Keep track of the override buffer;
|
|
|
|
SavedMainFileBuffer = OverrideMainBuffer;
|
2010-08-20 08:02:33 +08:00
|
|
|
} else {
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.second = 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
|
|
|
}
|
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
llvm::OwningPtr<TopLevelDeclTrackerAction> Act;
|
|
|
|
Act.reset(new TopLevelDeclTrackerAction(*this));
|
2009-12-04 16:17:33 +08:00
|
|
|
if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
|
2010-06-08 07:23:06 +08:00
|
|
|
Clang.getFrontendOpts().Inputs[0].first))
|
2009-12-01 17:51:01 +08:00
|
|
|
goto error;
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-04 16:17:33 +08:00
|
|
|
Act->Execute();
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2009-12-02 05:57:33 +08:00
|
|
|
// Steal the created target, context, and preprocessor, and take back the
|
|
|
|
// source and file managers.
|
2010-08-13 11:15:25 +08:00
|
|
|
TheSema.reset(Clang.takeSema());
|
|
|
|
Consumer.reset(Clang.takeASTConsumer());
|
2010-07-20 05:46:24 +08:00
|
|
|
Ctx.reset(Clang.takeASTContext());
|
|
|
|
PP.reset(Clang.takePreprocessor());
|
2009-12-01 17:51:01 +08:00
|
|
|
Clang.takeSourceManager();
|
|
|
|
Clang.takeFileManager();
|
2010-07-20 05:46:24 +08:00
|
|
|
Target.reset(Clang.takeTarget());
|
|
|
|
|
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
|
|
|
|
|
|
|
// Remove the overridden buffer we used for the preamble.
|
2010-08-05 00:47:14 +08:00
|
|
|
if (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
|
|
|
PreprocessorOpts.eraseRemappedFile(
|
|
|
|
PreprocessorOpts.remapped_file_buffer_end() - 1);
|
2010-08-05 00:47:14 +08:00
|
|
|
PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
|
|
|
|
}
|
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
Invocation.reset(Clang.takeInvocation());
|
2010-12-10 05:27:43 +08:00
|
|
|
|
|
|
|
if (ShouldCacheCodeCompletionResults) {
|
|
|
|
if (CacheCodeCompletionCoolDown > 0)
|
|
|
|
--CacheCodeCompletionCoolDown;
|
|
|
|
else if (top_level_size() != NumTopLevelDeclsAtLastCompletionCache)
|
|
|
|
CacheCodeCompletionResults();
|
|
|
|
}
|
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
return false;
|
|
|
|
|
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) {
|
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
|
|
|
PreprocessorOpts.eraseRemappedFile(
|
|
|
|
PreprocessorOpts.remapped_file_buffer_end() - 1);
|
2010-08-05 00:47:14 +08:00
|
|
|
PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
|
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
|
|
|
}
|
Introduce basic support for loading a precompiled preamble while
reparsing an ASTUnit. When saving a preamble, create a buffer larger
than the actual file we're working with but fill everything from the
end of the preamble to the end of the file with spaces (so the lexer
will quickly skip them). When we load the file, create a buffer of the
same size, filling it with the file and then spaces. Then, instruct
the lexer to start lexing after the preamble, therefore continuing the
parse from the spot where the preamble left off.
It's now possible to perform a simple preamble build + parse (+
reparse) with ASTUnit. However, one has to disable a bunch of checking
in the PCH reader to do so. That part isn't committed; it will likely
be handled with some other kind of flag (e.g., -fno-validate-pch).
As part of this, fix some issues with null termination of the memory
buffers created for the preamble; we were trying to explicitly
NULL-terminate them, even though they were also getting implicitly
NULL terminated, leading to excess warnings about NULL characters in
source files.
llvm-svn: 109445
2010-07-27 05:36:20 +08:00
|
|
|
|
2010-10-13 00:25:54 +08:00
|
|
|
StoredDiagnostics.clear();
|
2009-12-01 17:51:01 +08:00
|
|
|
Clang.takeSourceManager();
|
|
|
|
Clang.takeFileManager();
|
2010-07-20 05:46:24 +08:00
|
|
|
Invocation.reset(Clang.takeInvocation());
|
|
|
|
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");
|
2010-07-23 08:33:23 +08:00
|
|
|
if (P.createTemporaryFileOnDisk())
|
|
|
|
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;
|
2010-07-23 08:33:23 +08:00
|
|
|
llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
|
|
|
|
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) {
|
2010-11-04 06:45:23 +08:00
|
|
|
Buffer = getBufferForFile(FrontendOpts.Inputs[0].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-08-10 04:45:32 +08:00
|
|
|
return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, 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,
|
|
|
|
llvm::StringRef NewName) {
|
|
|
|
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(
|
2010-08-20 08:59:43 +08:00
|
|
|
CompilerInvocation PreambleInvocation,
|
2010-08-10 04:45:32 +08:00
|
|
|
bool AllowRebuild,
|
|
|
|
unsigned MaxLines) {
|
2010-07-24 07:58:40 +08:00
|
|
|
FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts();
|
|
|
|
PreprocessorOptions &PreprocessorOpts
|
|
|
|
= PreambleInvocation.getPreprocessorOpts();
|
|
|
|
|
|
|
|
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
|
2010-08-10 04:45:32 +08:00
|
|
|
= ComputePreamble(PreambleInvocation, MaxLines, CreatedPreambleBuffer);
|
2010-07-24 07:58:40 +08:00
|
|
|
|
2010-11-17 04:45:51 +08:00
|
|
|
// If ComputePreamble() Take ownership of the
|
|
|
|
llvm::OwningPtr<llvm::MemoryBuffer> OwnedPreambleBuffer;
|
|
|
|
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();
|
|
|
|
if (!PreambleFile.empty()) {
|
2010-07-31 04:58:08 +08:00
|
|
|
llvm::sys::Path(PreambleFile).eraseFromDisk();
|
2010-07-24 07:58:40 +08:00
|
|
|
PreambleFile.clear();
|
|
|
|
}
|
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 &&
|
2010-07-24 07:58:40 +08:00
|
|
|
memcmp(&Preamble[0], 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;
|
|
|
|
if (stat(R->second.c_str(), &StatBuf)) {
|
|
|
|
// 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;
|
|
|
|
if (stat(F->first(), &StatBuf)) {
|
|
|
|
// 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.
|
2010-10-12 05:37:58 +08:00
|
|
|
// FIXME: This won't catch any #pragma push warning changes that
|
|
|
|
// have occurred in the preamble.
|
2010-08-03 04:51:39 +08:00
|
|
|
getDiagnostics().Reset();
|
2010-10-12 05:37:58 +08:00
|
|
|
ProcessWarningOptions(getDiagnostics(),
|
|
|
|
PreambleInvocation.getDiagnosticOpts());
|
2010-08-03 04:51:39 +08:00
|
|
|
getDiagnostics().setNumWarnings(NumWarningsInPreamble);
|
|
|
|
if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble)
|
|
|
|
StoredDiagnostics.erase(
|
|
|
|
StoredDiagnostics.begin() + NumStoredDiagnosticsInPreamble,
|
|
|
|
StoredDiagnostics.end());
|
|
|
|
|
|
|
|
// 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,
|
|
|
|
FrontendOpts.Inputs[0].second);
|
|
|
|
}
|
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();
|
2010-07-31 04:58:08 +08:00
|
|
|
llvm::sys::Path(PreambleFile).eraseFromDisk();
|
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.
|
|
|
|
Preamble.assign(NewPreamble.first->getBufferStart(),
|
|
|
|
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,
|
2010-07-23 08:33:23 +08:00
|
|
|
FrontendOpts.Inputs[0].second);
|
|
|
|
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.
|
2010-07-24 07:58:40 +08:00
|
|
|
llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second);
|
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;
|
2010-10-01 09:05:22 +08:00
|
|
|
FrontendOpts.ChainedPCH = true;
|
2010-07-23 08:33:23 +08:00
|
|
|
// 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.
|
|
|
|
CompilerInstance Clang;
|
|
|
|
Clang.setInvocation(&PreambleInvocation);
|
|
|
|
OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
|
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Set up diagnostics, capturing all of the diagnostics produced.
|
2010-07-23 08:33:23 +08:00
|
|
|
Clang.setDiagnostics(&getDiagnostics());
|
|
|
|
|
|
|
|
// Create the target instance.
|
2011-01-28 02:02:58 +08:00
|
|
|
Clang.getTargetOpts().Features = TargetFeatures;
|
2010-07-23 08:33:23 +08:00
|
|
|
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
|
|
|
Clang.getTargetOpts()));
|
|
|
|
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.
|
|
|
|
Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
|
|
|
|
|
|
|
|
assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
|
|
|
|
"Invocation must have exactly one source file!");
|
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
|
|
|
|
"FIXME: AST inputs not yet supported here!");
|
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
|
|
|
|
"IR inputs not support here!");
|
|
|
|
|
|
|
|
// Clear out old caches and data.
|
2010-10-08 12:03:57 +08:00
|
|
|
getDiagnostics().Reset();
|
2010-10-12 05:37:58 +08:00
|
|
|
ProcessWarningOptions(getDiagnostics(), Clang.getDiagnosticOpts());
|
2010-10-12 08:50:20 +08:00
|
|
|
StoredDiagnostics.erase(
|
|
|
|
StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
|
|
|
|
StoredDiagnostics.end());
|
2010-08-04 03:06:41 +08:00
|
|
|
TopLevelDecls.clear();
|
|
|
|
TopLevelDeclsInPreamble.clear();
|
2010-11-30 14:16:57 +08:00
|
|
|
PreprocessedEntities.clear();
|
|
|
|
PreprocessedEntitiesInPreamble.clear();
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create a file manager object to provide access to and cache the filesystem.
|
2010-11-23 15:51:02 +08:00
|
|
|
Clang.setFileManager(new FileManager(Clang.getFileSystemOpts()));
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create the source manager.
|
2010-11-04 06:45:23 +08:00
|
|
|
Clang.setSourceManager(new SourceManager(getDiagnostics(),
|
2010-11-23 16:35:12 +08:00
|
|
|
Clang.getFileManager()));
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2010-08-03 16:14:03 +08:00
|
|
|
llvm::OwningPtr<PrecompilePreambleAction> Act;
|
|
|
|
Act.reset(new PrecompilePreambleAction(*this));
|
2010-07-23 08:33:23 +08:00
|
|
|
if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
|
|
|
|
Clang.getFrontendOpts().Inputs[0].first)) {
|
|
|
|
Clang.takeInvocation();
|
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();
|
|
|
|
Clang.takeInvocation();
|
|
|
|
|
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-11-30 14:16:57 +08:00
|
|
|
PreprocessedEntities.clear();
|
|
|
|
PreprocessedEntitiesInPreamble.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
|
|
|
}
|
|
|
|
|
|
|
|
// Keep track of the preamble we precompiled.
|
|
|
|
PreambleFile = FrontendOpts.OutputFile;
|
2010-08-03 04:51:39 +08:00
|
|
|
NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
|
|
|
|
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();
|
|
|
|
SourceManager &SourceMgr = Clang.getSourceManager();
|
|
|
|
const llvm::MemoryBuffer *MainFileBuffer
|
|
|
|
= SourceMgr.getBuffer(SourceMgr.getMainFileID());
|
|
|
|
for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(),
|
|
|
|
FEnd = SourceMgr.fileinfo_end();
|
|
|
|
F != FEnd;
|
|
|
|
++F) {
|
|
|
|
const FileEntry *File = F->second->Entry;
|
|
|
|
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);
|
2010-07-24 08:38:13 +08:00
|
|
|
return CreatePaddedMainFileBuffer(NewPreamble.first,
|
|
|
|
PreambleReservedSize,
|
|
|
|
FrontendOpts.Inputs[0].second);
|
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());
|
|
|
|
}
|
|
|
|
|
2010-11-30 14:16:57 +08:00
|
|
|
void ASTUnit::RealizePreprocessedEntitiesFromPreamble() {
|
|
|
|
if (!PP)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PreprocessingRecord *PPRec = PP->getPreprocessingRecord();
|
|
|
|
if (!PPRec)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ExternalPreprocessingRecordSource *External = PPRec->getExternalSource();
|
|
|
|
if (!External)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = PreprocessedEntitiesInPreamble.size(); I != N; ++I) {
|
|
|
|
if (PreprocessedEntity *PE
|
|
|
|
= External->ReadPreprocessedEntity(PreprocessedEntitiesInPreamble[I]))
|
|
|
|
PreprocessedEntities.push_back(PE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PreprocessedEntities.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
PreprocessedEntities.insert(PreprocessedEntities.end(),
|
|
|
|
PPRec->begin(true), PPRec->end(true));
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTUnit::pp_entity_iterator ASTUnit::pp_entity_begin() {
|
|
|
|
if (!PreprocessedEntitiesInPreamble.empty() &&
|
|
|
|
PreprocessedEntities.empty())
|
|
|
|
RealizePreprocessedEntitiesFromPreamble();
|
|
|
|
|
|
|
|
if (PreprocessedEntities.empty())
|
|
|
|
if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
|
|
|
|
return PPRec->begin(true);
|
|
|
|
|
|
|
|
return PreprocessedEntities.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTUnit::pp_entity_iterator ASTUnit::pp_entity_end() {
|
|
|
|
if (!PreprocessedEntitiesInPreamble.empty() &&
|
|
|
|
PreprocessedEntities.empty())
|
|
|
|
RealizePreprocessedEntitiesFromPreamble();
|
|
|
|
|
|
|
|
if (PreprocessedEntities.empty())
|
|
|
|
if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord())
|
|
|
|
return PPRec->end(true);
|
|
|
|
|
|
|
|
return PreprocessedEntities.end();
|
|
|
|
}
|
|
|
|
|
2010-08-04 03:06:41 +08:00
|
|
|
unsigned ASTUnit::getMaxPCHLevel() const {
|
|
|
|
if (!getOnlyLocalDecls())
|
|
|
|
return Decl::MaxPCHLevel;
|
|
|
|
|
2010-10-06 00:15:19 +08:00
|
|
|
return 0;
|
2010-08-04 03:06:41 +08:00
|
|
|
}
|
|
|
|
|
2010-10-28 23:44:59 +08:00
|
|
|
llvm::StringRef ASTUnit::getMainFileName() const {
|
|
|
|
return Invocation->getFrontendOpts().Inputs[0].second;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2011-01-28 02:02:58 +08:00
|
|
|
// Save the target features.
|
|
|
|
TargetFeatures = Invocation->getTargetOpts().Features;
|
|
|
|
|
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
|
|
|
|
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,
|
|
|
|
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
|
|
|
bool OnlyLocalDecls,
|
2010-07-23 08:33:23 +08:00
|
|
|
bool CaptureDiagnostics,
|
2010-08-10 04:45:32 +08:00
|
|
|
bool PrecompilePreamble,
|
2010-08-14 06:48:40 +08:00
|
|
|
bool CompleteTranslationUnit,
|
2010-11-11 08:39:14 +08:00
|
|
|
bool CacheCodeCompletionResults) {
|
2010-07-20 05:46:24 +08:00
|
|
|
// Create the AST unit.
|
|
|
|
llvm::OwningPtr<ASTUnit> AST;
|
|
|
|
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;
|
2010-08-10 04:45:32 +08:00
|
|
|
AST->CompleteTranslationUnit = CompleteTranslationUnit;
|
2010-08-14 06:48:40 +08:00
|
|
|
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
|
2010-11-16 07:00:34 +08:00
|
|
|
AST->CacheCodeCompletionCoolDown = 1;
|
2010-07-20 05:46:24 +08:00
|
|
|
AST->Invocation.reset(CI);
|
2010-07-31 04:58:08 +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,
|
2010-04-06 07:52:57 +08:00
|
|
|
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
2009-12-13 11:46:13 +08:00
|
|
|
llvm::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,
|
2010-08-10 04:45:32 +08:00
|
|
|
bool PrecompilePreamble,
|
2010-08-14 06:48:40 +08:00
|
|
|
bool CompleteTranslationUnit,
|
2010-10-28 01:24:53 +08:00
|
|
|
bool CacheCodeCompletionResults,
|
|
|
|
bool CXXPrecompilePreamble,
|
|
|
|
bool CXXChainedPCH) {
|
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
|
|
|
llvm::SmallVector<const char *, 16> Args;
|
|
|
|
Args.push_back("<clang>"); // FIXME: Remove dummy argument.
|
|
|
|
Args.insert(Args.end(), ArgBegin, ArgEnd);
|
|
|
|
|
|
|
|
// FIXME: Find a cleaner way to force the driver into restricted modes. We
|
|
|
|
// also want to force it to use clang.
|
|
|
|
Args.push_back("-fsyntax-only");
|
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
|
|
|
|
|
|
|
|
llvm::OwningPtr<CompilerInvocation> CI;
|
2010-11-11 08:39:14 +08:00
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
{
|
2010-11-11 08:39:14 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
|
2010-10-12 08:50:20 +08:00
|
|
|
StoredDiagnostics);
|
|
|
|
|
|
|
|
// FIXME: We shouldn't have to pass in the path info.
|
|
|
|
driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
|
|
|
|
"a.out", false, false, *Diags);
|
|
|
|
|
|
|
|
// Don't check that inputs exist, they have been remapped.
|
|
|
|
TheDriver.setCheckInputsExist(false);
|
|
|
|
|
|
|
|
llvm::OwningPtr<driver::Compilation> C(
|
|
|
|
TheDriver.BuildCompilation(Args.size(), Args.data()));
|
|
|
|
|
|
|
|
// We expect to get back exactly one command job, if we didn't something
|
|
|
|
// failed.
|
|
|
|
const driver::JobList &Jobs = C->getJobs();
|
|
|
|
if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
|
|
|
|
llvm::SmallString<256> Msg;
|
|
|
|
llvm::raw_svector_ostream OS(Msg);
|
|
|
|
C->PrintJob(OS, C->getJobs(), "; ", true);
|
|
|
|
Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
|
|
|
|
return 0;
|
|
|
|
}
|
2009-12-02 11:23:45 +08:00
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
|
|
|
|
if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
|
|
|
|
Diags->Report(diag::err_fe_expected_clang_command);
|
|
|
|
return 0;
|
|
|
|
}
|
2009-12-02 11:23:45 +08:00
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
const driver::ArgStringList &CCArgs = Cmd->getArguments();
|
|
|
|
CI.reset(new CompilerInvocation);
|
|
|
|
CompilerInvocation::CreateFromArgs(*CI,
|
2010-11-11 08:39:14 +08:00
|
|
|
const_cast<const char **>(CCArgs.data()),
|
|
|
|
const_cast<const char **>(CCArgs.data()) +
|
2010-10-12 08:50:20 +08:00
|
|
|
CCArgs.size(),
|
|
|
|
*Diags);
|
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
|
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I)
|
2010-01-31 05:47:16 +08:00
|
|
|
CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
|
2010-02-16 09:55:04 +08:00
|
|
|
RemappedFiles[I].second);
|
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
|
|
|
|
2010-10-28 01:24:53 +08:00
|
|
|
// Check whether we should precompile the preamble and/or use chained PCH.
|
|
|
|
// FIXME: This is a temporary hack while we debug C++ chained PCH.
|
|
|
|
if (CI->getLangOpts().CPlusPlus) {
|
|
|
|
PrecompilePreamble = PrecompilePreamble && CXXPrecompilePreamble;
|
|
|
|
|
|
|
|
if (PrecompilePreamble && !CXXChainedPCH &&
|
|
|
|
!CI->getPreprocessorOpts().ImplicitPCHInclude.empty())
|
|
|
|
PrecompilePreamble = false;
|
|
|
|
}
|
|
|
|
|
2010-10-12 08:50:20 +08:00
|
|
|
// Create the AST unit.
|
|
|
|
llvm::OwningPtr<ASTUnit> AST;
|
|
|
|
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;
|
2010-11-23 16:35:12 +08:00
|
|
|
|
|
|
|
AST->FileMgr.reset(new FileManager(FileSystemOptions()));
|
2010-10-12 08:50:20 +08:00
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
2010-11-11 08:39:14 +08:00
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
2010-10-12 08:50:20 +08:00
|
|
|
AST->CompleteTranslationUnit = CompleteTranslationUnit;
|
|
|
|
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
|
2010-11-16 07:00:34 +08:00
|
|
|
AST->CacheCodeCompletionCoolDown = 1;
|
2010-10-12 08:50:20 +08:00
|
|
|
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
|
|
|
|
AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
|
|
|
|
AST->StoredDiagnostics.swap(StoredDiagnostics);
|
|
|
|
AST->Invocation.reset(CI.take());
|
2010-11-23 16:35:12 +08:00
|
|
|
return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : 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) {
|
|
|
|
if (!Invocation.get())
|
|
|
|
return true;
|
|
|
|
|
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();
|
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I)
|
|
|
|
Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
|
|
|
|
RemappedFiles[I].second);
|
|
|
|
|
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;
|
2010-08-04 13:53:38 +08:00
|
|
|
if (!PreambleFile.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.
|
2010-10-12 05:37:58 +08:00
|
|
|
if (!OverrideMainBuffer) {
|
2010-08-03 04:51:39 +08:00
|
|
|
getDiagnostics().Reset();
|
2010-10-12 05:37:58 +08:00
|
|
|
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
|
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// Parse the sources
|
2010-07-24 08:38:13 +08:00
|
|
|
bool Result = Parse(OverrideMainBuffer);
|
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 {
|
|
|
|
unsigned NormalContexts;
|
|
|
|
ASTUnit &AST;
|
|
|
|
CodeCompleteConsumer &Next;
|
|
|
|
|
|
|
|
public:
|
|
|
|
AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next,
|
2010-08-15 14:18:01 +08:00
|
|
|
bool IncludeMacros, bool IncludeCodePatterns,
|
|
|
|
bool IncludeGlobals)
|
|
|
|
: CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals,
|
2010-08-14 06:48:40 +08:00
|
|
|
Next.isOutputBinary()), AST(AST), Next(Next)
|
|
|
|
{
|
|
|
|
// Compute the set of contexts in which we will look when we don't have
|
|
|
|
// any information about the specific context.
|
|
|
|
NormalContexts
|
|
|
|
= (1 << (CodeCompletionContext::CCC_TopLevel - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCInterface - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Statement - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Expression - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_MemberAccess - 1))
|
2010-09-15 07:59:36 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1))
|
2010-09-24 07:01:17 +08:00
|
|
|
| (1 << (CodeCompletionContext::CCC_ParenthesizedExpression - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Recovery - 1));
|
2010-09-15 07:59:36 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
if (AST.getASTContext().getLangOptions().CPlusPlus)
|
|
|
|
NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_UnionTag - 1))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
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:
|
|
|
|
case CodeCompletionContext::CCC_MemberAccess:
|
|
|
|
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:
|
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:
|
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);
|
2010-08-17 05:18:39 +08:00
|
|
|
if (Ctx.getLangOptions().CPlusPlus)
|
|
|
|
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;
|
2010-08-17 05:18:39 +08:00
|
|
|
unsigned InContexts
|
2010-09-24 07:01:17 +08:00
|
|
|
= (Context.getKind() == CodeCompletionContext::CCC_Recovery? NormalContexts
|
2010-08-17 05:18:39 +08:00
|
|
|
: (1 << (Context.getKind() - 1)));
|
|
|
|
|
|
|
|
// 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;
|
2010-08-17 04:01:48 +08:00
|
|
|
llvm::SmallVector<Result, 8> AllResults;
|
|
|
|
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-26 02:03:13 +08:00
|
|
|
CXCursorKind CursorKind = C->Kind;
|
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(),
|
2010-09-21 05:11:48 +08:00
|
|
|
S.getLangOptions(),
|
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.
|
2011-02-02 03:23:04 +08:00
|
|
|
CodeCompletionBuilder Builder(getAllocator(), CCP_CodePattern,
|
|
|
|
C->Availability);
|
|
|
|
Builder.AddTypedTextChunk(C->Completion->getTypedText());
|
2010-08-26 02:03:13 +08:00
|
|
|
CursorKind = CXCursor_NotImplemented;
|
|
|
|
Priority = CCP_CodePattern;
|
2011-02-02 03:23:04 +08:00
|
|
|
Completion = Builder.TakeString();
|
2010-08-25 04:21:13 +08:00
|
|
|
}
|
|
|
|
|
2010-08-26 02:03:13 +08:00
|
|
|
AllResults.push_back(Result(Completion, Priority, CursorKind,
|
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());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
|
|
|
|
RemappedFile *RemappedFiles,
|
|
|
|
unsigned NumRemappedFiles,
|
2010-08-05 17:09:23 +08:00
|
|
|
bool IncludeMacros,
|
|
|
|
bool IncludeCodePatterns,
|
2010-08-05 00:47:14 +08:00
|
|
|
CodeCompleteConsumer &Consumer,
|
|
|
|
Diagnostic &Diag, LangOptions &LangOpts,
|
|
|
|
SourceManager &SourceMgr, FileManager &FileMgr,
|
2010-08-20 08:59:43 +08:00
|
|
|
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics,
|
|
|
|
llvm::SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) {
|
2010-08-05 00:47:14 +08:00
|
|
|
if (!Invocation.get())
|
|
|
|
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 + ":" +
|
|
|
|
llvm::Twine(Line) + ":" + llvm::Twine(Column));
|
2010-08-10 04:45:32 +08:00
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
CompilerInvocation CCInvocation(*Invocation);
|
|
|
|
FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts();
|
|
|
|
PreprocessorOptions &PreprocessorOpts = CCInvocation.getPreprocessorOpts();
|
2010-08-05 17:09:23 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
FrontendOpts.ShowMacrosInCodeCompletion
|
|
|
|
= IncludeMacros && CachedCompletionResults.empty();
|
2010-08-05 17:09:23 +08:00
|
|
|
FrontendOpts.ShowCodePatternsInCodeCompletion = IncludeCodePatterns;
|
2010-08-15 14:18:01 +08:00
|
|
|
FrontendOpts.ShowGlobalSymbolsInCodeCompletion
|
|
|
|
= CachedCompletionResults.empty();
|
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.
|
|
|
|
LangOpts = CCInvocation.getLangOpts();
|
|
|
|
|
|
|
|
CompilerInstance Clang;
|
|
|
|
Clang.setInvocation(&CCInvocation);
|
|
|
|
OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second;
|
|
|
|
|
|
|
|
// Set up diagnostics, capturing any diagnostics produced.
|
|
|
|
Clang.setDiagnostics(&Diag);
|
2010-10-12 05:37:58 +08:00
|
|
|
ProcessWarningOptions(Diag, CCInvocation.getDiagnosticOpts());
|
2010-08-05 00:47:14 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(true,
|
2010-11-11 08:39:14 +08:00
|
|
|
Clang.getDiagnostics(),
|
2010-08-05 00:47:14 +08:00
|
|
|
StoredDiagnostics);
|
|
|
|
|
|
|
|
// Create the target instance.
|
2011-01-28 02:02:58 +08:00
|
|
|
Clang.getTargetOpts().Features = TargetFeatures;
|
2010-08-05 00:47:14 +08:00
|
|
|
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
|
|
|
Clang.getTargetOpts()));
|
|
|
|
if (!Clang.hasTarget()) {
|
|
|
|
Clang.takeInvocation();
|
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.
|
|
|
|
Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
|
|
|
|
|
|
|
|
assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
|
|
|
|
"Invocation must have exactly one source file!");
|
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST &&
|
|
|
|
"FIXME: AST inputs not yet supported here!");
|
|
|
|
assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
|
|
|
|
"IR inputs not support here!");
|
|
|
|
|
|
|
|
|
|
|
|
// Use the source and file managers that we were given.
|
|
|
|
Clang.setFileManager(&FileMgr);
|
|
|
|
Clang.setSourceManager(&SourceMgr);
|
|
|
|
|
|
|
|
// 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) {
|
2010-08-05 00:47:14 +08:00
|
|
|
PreprocessorOpts.addRemappedFile(RemappedFiles[I].first,
|
|
|
|
RemappedFiles[I].second);
|
2010-08-20 08:59:43 +08:00
|
|
|
OwnedBuffers.push_back(RemappedFiles[I].second);
|
|
|
|
}
|
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
|
|
|
|
= new AugmentedCodeCompleteConsumer(*this, Consumer,
|
|
|
|
FrontendOpts.ShowMacrosInCodeCompletion,
|
|
|
|
FrontendOpts.ShowCodePatternsInCodeCompletion,
|
|
|
|
FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
|
|
|
|
Clang.setCodeCompletionConsumer(AugmentedConsumer);
|
2010-08-05 00:47:14 +08:00
|
|
|
|
2010-08-10 04:45:32 +08:00
|
|
|
// If we have a precompiled preamble, try to use it. We only allow
|
|
|
|
// the use of the precompiled preamble if we're if the completion
|
|
|
|
// point is within the main file, after the end of the precompiled
|
|
|
|
// preamble.
|
|
|
|
llvm::MemoryBuffer *OverrideMainBuffer = 0;
|
|
|
|
if (!PreambleFile.empty()) {
|
|
|
|
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())
|
|
|
|
if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID())
|
2010-08-20 08:59:43 +08:00
|
|
|
OverrideMainBuffer
|
2010-08-26 02:04:15 +08:00
|
|
|
= getMainBufferWithPrecompiledPreamble(CCInvocation, false,
|
|
|
|
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(),
|
|
|
|
this->StoredDiagnostics.begin(),
|
|
|
|
this->StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver);
|
2010-08-10 04:45:32 +08:00
|
|
|
if (OverrideMainBuffer) {
|
|
|
|
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
|
|
|
|
PreprocessorOpts.PrecompiledPreambleBytes.second
|
|
|
|
= PreambleEndsAtStartOfLine;
|
|
|
|
PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
|
|
|
|
PreprocessorOpts.DisablePCHValidation = true;
|
|
|
|
|
|
|
|
// The stored diagnostics have the old source manager. Copy them
|
|
|
|
// to our output set of stored diagnostics, updating the source
|
|
|
|
// manager to the one we were given.
|
2010-10-12 08:50:20 +08:00
|
|
|
for (unsigned I = NumStoredDiagnosticsFromDriver,
|
|
|
|
N = this->StoredDiagnostics.size();
|
|
|
|
I < N; ++I) {
|
2010-08-10 04:45:32 +08:00
|
|
|
StoredDiagnostics.push_back(this->StoredDiagnostics[I]);
|
|
|
|
FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr);
|
|
|
|
StoredDiagnostics[I].setLocation(Loc);
|
|
|
|
}
|
2010-10-12 08:50:20 +08:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
llvm::OwningPtr<SyntaxOnlyAction> Act;
|
|
|
|
Act.reset(new SyntaxOnlyAction);
|
|
|
|
if (Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
|
|
|
|
Clang.getFrontendOpts().Inputs[0].first)) {
|
|
|
|
Act->Execute();
|
|
|
|
Act->EndSourceFile();
|
|
|
|
}
|
2010-08-10 04:45:32 +08:00
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// Steal back our resources.
|
|
|
|
Clang.takeFileManager();
|
|
|
|
Clang.takeSourceManager();
|
|
|
|
Clang.takeInvocation();
|
|
|
|
}
|
2010-08-13 13:36:37 +08:00
|
|
|
|
|
|
|
bool ASTUnit::Save(llvm::StringRef File) {
|
|
|
|
if (getDiagnostics().hasErrorOccurred())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
|
|
|
|
// unconditionally create a stat cache when we parse the file?
|
|
|
|
std::string ErrorInfo;
|
2010-08-16 00:54:31 +08:00
|
|
|
llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo,
|
|
|
|
llvm::raw_fd_ostream::F_Binary);
|
2010-08-13 13:36:37 +08:00
|
|
|
if (!ErrorInfo.empty() || Out.has_error())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
std::vector<unsigned char> Buffer;
|
|
|
|
llvm::BitstreamWriter Stream(Buffer);
|
2010-08-19 07:56:21 +08:00
|
|
|
ASTWriter Writer(Stream);
|
|
|
|
Writer.WriteAST(getSema(), 0, 0);
|
2010-08-13 13:36:37 +08:00
|
|
|
|
|
|
|
// Write the generated bitstream to "Out".
|
2010-08-19 06:29:43 +08:00
|
|
|
if (!Buffer.empty())
|
|
|
|
Out.write((char *)&Buffer.front(), Buffer.size());
|
2010-08-13 13:36:37 +08:00
|
|
|
Out.close();
|
|
|
|
return Out.has_error();
|
|
|
|
}
|