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-08-18 04:43:28 +08:00
|
|
|
#include "clang/Serialization/PCHReader.h"
|
|
|
|
#include "clang/Serialization/PCHWriter.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-01-23 08:14:00 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2009-12-02 11:23:45 +08:00
|
|
|
#include "llvm/System/Host.h"
|
2009-10-18 19:34:14 +08:00
|
|
|
#include "llvm/System/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-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-04-06 05:10:19 +08:00
|
|
|
ASTUnit::ASTUnit(bool _MainFileIsAST)
|
2010-07-20 05:46:24 +08:00
|
|
|
: CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST),
|
2010-08-10 04:45:32 +08:00
|
|
|
CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked),
|
2010-08-14 06:48:40 +08:00
|
|
|
PreambleRebuildCounter(0), SavedMainFileBuffer(0),
|
2010-08-17 08:40:40 +08:00
|
|
|
ShouldCacheCodeCompletionResults(false),
|
|
|
|
NumTopLevelDeclsAtLastCompletionCache(0),
|
|
|
|
CacheCodeCompletionCoolDown(0) {
|
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-07-31 04:58:08 +08:00
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
ClearCachedCompletionResults();
|
|
|
|
|
2010-07-31 04:58:08 +08:00
|
|
|
for (unsigned I = 0, N = Timers.size(); I != N; ++I)
|
|
|
|
delete Timers[I];
|
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))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Type - 1));
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
} else if (isa<ClassTemplateDecl>(ND) || isa<TemplateTemplateParmDecl>(ND))
|
|
|
|
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))
|
|
|
|
| (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;
|
|
|
|
|
|
|
|
llvm::Timer *CachingTimer = 0;
|
|
|
|
if (TimerGroup.get()) {
|
|
|
|
CachingTimer = new llvm::Timer("Cache global code completions",
|
|
|
|
*TimerGroup);
|
|
|
|
CachingTimer->startTimer();
|
|
|
|
Timers.push_back(CachingTimer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear out the previous results.
|
|
|
|
ClearCachedCompletionResults();
|
|
|
|
|
|
|
|
// Gather the set of global code completions.
|
|
|
|
typedef CodeCompleteConsumer::Result Result;
|
|
|
|
llvm::SmallVector<Result, 8> Results;
|
|
|
|
TheSema->GatherGlobalCodeCompletions(Results);
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
|
|
|
|
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-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))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_Type - 1));
|
|
|
|
|
|
|
|
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;
|
|
|
|
CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
|
|
|
|
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;
|
|
|
|
CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema);
|
|
|
|
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))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1));
|
|
|
|
CachedResult.Priority = Results[I].Priority;
|
|
|
|
CachedResult.Kind = Results[I].CursorKind;
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Results[I].Destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CachingTimer)
|
|
|
|
CachingTimer->stopTimer();
|
2010-08-17 08:40:40 +08:00
|
|
|
|
|
|
|
// Make a note of the state when we performed this caching.
|
|
|
|
NumTopLevelDeclsAtLastCompletionCache = top_level_size();
|
|
|
|
CacheCodeCompletionCoolDown = 15;
|
2010-08-14 06:48:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASTUnit::ClearCachedCompletionResults() {
|
|
|
|
for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I)
|
|
|
|
delete CachedCompletionResults[I].Completion;
|
|
|
|
CachedCompletionResults.clear();
|
2010-08-17 02:08:11 +08:00
|
|
|
CachedCompletionTypes.clear();
|
2010-08-14 06:48:40 +08:00
|
|
|
}
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
/// \brief Gathers information from PCHReader that will be used to initialize
|
|
|
|
/// a Preprocessor.
|
2009-11-28 18:07:24 +08:00
|
|
|
class PCHInfoCollector : public PCHReaderListener {
|
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:
|
|
|
|
PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI,
|
|
|
|
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,
|
|
|
|
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) {
|
|
|
|
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
|
|
|
|
2009-10-16 06:23:48 +08:00
|
|
|
const std::string &ASTUnit::getPCHFileName() {
|
2009-12-03 05:47:43 +08:00
|
|
|
assert(isMainFileAST() && "Not an ASTUnit from a PCH file!");
|
2010-01-31 00:23:25 +08:00
|
|
|
return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName();
|
2009-10-16 06:23:48 +08:00
|
|
|
}
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
|
2010-04-06 07:52:57 +08:00
|
|
|
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
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));
|
|
|
|
|
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;
|
2010-04-06 07:52:57 +08:00
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
2010-04-06 05:10:19 +08:00
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
2009-10-17 04:01:17 +08:00
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
2010-04-06 07:52:57 +08:00
|
|
|
AST->Diagnostics = Diags;
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->FileMgr.reset(new FileManager);
|
|
|
|
AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
|
2009-10-19 22:34:22 +08:00
|
|
|
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
|
2010-08-13 11:15:25 +08:00
|
|
|
|
2010-02-19 02:08:43 +08:00
|
|
|
// If requested, capture diagnostics in the ASTUnit.
|
2010-04-06 05:10:19 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
|
2010-04-06 02:10:21 +08:00
|
|
|
AST->StoredDiagnostics);
|
2010-02-19 02:08:43 +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(),
|
|
|
|
0);
|
|
|
|
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;
|
|
|
|
|
2009-09-03 13:59:50 +08:00
|
|
|
llvm::OwningPtr<PCHReader> Reader;
|
2009-06-20 16:08:23 +08:00
|
|
|
|
2009-10-20 05:44:57 +08:00
|
|
|
Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(),
|
2010-04-06 05:10:19 +08:00
|
|
|
AST->getDiagnostics()));
|
2009-09-03 13:59:35 +08:00
|
|
|
Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple,
|
|
|
|
Predefines, Counter));
|
|
|
|
|
|
|
|
switch (Reader->ReadPCH(Filename)) {
|
2009-06-20 16:08:23 +08:00
|
|
|
case PCHReader::Success:
|
|
|
|
break;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
case PCHReader::Failure:
|
2009-06-26 02:22:30 +08:00
|
|
|
case PCHReader::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();
|
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// PCH 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
|
|
|
//
|
|
|
|
// FIXME: This is broken, we should store the TargetOptions in the PCH.
|
|
|
|
TargetOptions TargetOpts;
|
|
|
|
TargetOpts.ABI = "";
|
2010-06-11 09:06:47 +08:00
|
|
|
TargetOpts.CXXABI = "itanium";
|
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
|
|
|
|
2009-06-20 16:08:23 +08:00
|
|
|
// Attach the PCH reader to the AST context as an external AST
|
|
|
|
// source, so that declarations will be deserialized from the
|
|
|
|
// PCH file as needed.
|
2010-08-13 11:15:25 +08:00
|
|
|
PCHReader *ReaderPtr = Reader.get();
|
|
|
|
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);
|
|
|
|
|
|
|
|
// Create a semantic analysis object and tell the PCH reader about it.
|
|
|
|
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-08-03 16:14:03 +08:00
|
|
|
class PrecompilePreambleConsumer : public PCHGenerator {
|
|
|
|
ASTUnit &Unit;
|
2010-08-04 03:06:41 +08:00
|
|
|
std::vector<Decl *> TopLevelDecls;
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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-07-20 05:46:24 +08:00
|
|
|
if (!Invocation.get())
|
|
|
|
return true;
|
|
|
|
|
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-08-05 00:47:14 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
|
|
|
|
getDiagnostics(),
|
|
|
|
StoredDiagnostics);
|
2010-04-06 05:10:19 +08:00
|
|
|
|
2009-12-01 17:51:01 +08:00
|
|
|
// Create the target instance.
|
|
|
|
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
|
|
|
Clang.getTargetOpts()));
|
2010-08-19 06:29:43 +08:00
|
|
|
if (!Clang.hasTarget())
|
2010-07-20 05:46:24 +08:00
|
|
|
return true;
|
|
|
|
|
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?
|
|
|
|
FileMgr.reset(new FileManager);
|
|
|
|
SourceMgr.reset(new SourceManager(getDiagnostics()));
|
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();
|
|
|
|
CleanTemporaryFiles();
|
|
|
|
PreprocessedEntitiesByFile.clear();
|
2010-08-03 04:51:39 +08:00
|
|
|
|
|
|
|
if (!OverrideMainBuffer)
|
|
|
|
StoredDiagnostics.clear();
|
2010-08-05 00:47:14 +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
|
|
|
|
|
|
|
// Keep track of the override buffer;
|
|
|
|
SavedMainFileBuffer = OverrideMainBuffer;
|
2010-08-03 04:51:39 +08:00
|
|
|
|
|
|
|
// The stored diagnostic has the old source manager in it; update
|
|
|
|
// the locations to refer into the new source manager. Since we've
|
|
|
|
// been careful to make sure that the source manager's state
|
|
|
|
// before and after are identical, so that we can reuse the source
|
|
|
|
// location itself.
|
|
|
|
for (unsigned I = 0, N = StoredDiagnostics.size(); I != N; ++I) {
|
|
|
|
FullSourceLoc Loc(StoredDiagnostics[I].getLocation(),
|
|
|
|
getSourceManager());
|
|
|
|
StoredDiagnostics[I].setLocation(Loc);
|
|
|
|
}
|
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-08-14 06:48:40 +08:00
|
|
|
|
|
|
|
// If we were asked to cache code-completion results and don't have any
|
|
|
|
// results yet, do so now.
|
|
|
|
if (ShouldCacheCodeCompletionResults && CachedCompletionResults.empty())
|
|
|
|
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-07-27 08:27:13 +08:00
|
|
|
PreprocessorOpts.DisablePCHValidation = true;
|
2010-08-05 00:47:14 +08:00
|
|
|
PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude;
|
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
|
|
|
|
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!
|
|
|
|
std::string Error;
|
|
|
|
const char *TmpDir = ::getenv("TMPDIR");
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = ::getenv("TEMP");
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = ::getenv("TMP");
|
|
|
|
if (!TmpDir)
|
|
|
|
TmpDir = "/tmp";
|
|
|
|
llvm::sys::Path P(TmpDir);
|
|
|
|
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-07-23 08:33:23 +08:00
|
|
|
PreprocessorOptions &PreprocessorOpts
|
2010-07-24 07:58:40 +08:00
|
|
|
= Invocation.getPreprocessorOpts();
|
|
|
|
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-07-23 08:33:23 +08:00
|
|
|
Buffer = llvm::MemoryBuffer::getFile(M->second);
|
|
|
|
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
|
|
|
|
2010-07-24 07:58:40 +08:00
|
|
|
// Remove this remapping. We've captured the buffer already.
|
2010-07-23 08:33:23 +08:00
|
|
|
M = PreprocessorOpts.eraseRemappedFile(M);
|
|
|
|
E = PreprocessorOpts.remapped_file_end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Remove this remapping. We've captured the buffer already.
|
2010-07-23 08:33:23 +08:00
|
|
|
M = PreprocessorOpts.eraseRemappedFile(M);
|
|
|
|
E = PreprocessorOpts.remapped_file_buffer_end();
|
|
|
|
}
|
|
|
|
}
|
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) {
|
|
|
|
Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
|
|
|
|
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,
|
|
|
|
bool DeleteOld,
|
|
|
|
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
|
|
|
|
|
|
|
if (DeleteOld)
|
|
|
|
delete Old;
|
|
|
|
|
|
|
|
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(
|
|
|
|
bool AllowRebuild,
|
|
|
|
unsigned MaxLines) {
|
2010-07-24 07:58:40 +08:00
|
|
|
CompilerInvocation PreambleInvocation(*Invocation);
|
|
|
|
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
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
delete NewPreamble.first;
|
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.
|
|
|
|
getDiagnostics().Reset();
|
|
|
|
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,
|
|
|
|
CreatedPreambleBuffer,
|
|
|
|
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-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-07-24 07:58:40 +08:00
|
|
|
// We did not previously compute a preamble, or it can't be reused anyway.
|
2010-07-31 04:58:08 +08:00
|
|
|
llvm::Timer *PreambleTimer = 0;
|
|
|
|
if (TimerGroup.get()) {
|
|
|
|
PreambleTimer = new llvm::Timer("Precompiling preamble", *TimerGroup);
|
|
|
|
PreambleTimer->startTimer();
|
|
|
|
Timers.push_back(PreambleTimer);
|
|
|
|
}
|
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-07-23 08:33:23 +08:00
|
|
|
llvm::MemoryBuffer *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-08-06 08:35:11 +08:00
|
|
|
// FIXME: Set ChainedPCH unconditionally, once it is ready.
|
|
|
|
if (::getenv("LIBCLANG_CHAINING"))
|
|
|
|
FrontendOpts.ChainedPCH = true;
|
2010-07-23 08:33:23 +08:00
|
|
|
// FIXME: Generate the precompiled header into memory?
|
2010-07-31 04:58:08 +08:00
|
|
|
FrontendOpts.OutputFile = GetPreamblePCHPath();
|
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());
|
2010-08-05 00:47:14 +08:00
|
|
|
CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
|
|
|
|
getDiagnostics(),
|
|
|
|
StoredDiagnostics);
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create the target instance.
|
|
|
|
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();
|
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
delete NewPreamble.first;
|
2010-07-31 04:58:08 +08:00
|
|
|
if (PreambleTimer)
|
|
|
|
PreambleTimer->stopTimer();
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
|
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.
|
|
|
|
StoredDiagnostics.clear();
|
2010-08-04 03:06:41 +08:00
|
|
|
TopLevelDecls.clear();
|
|
|
|
TopLevelDeclsInPreamble.clear();
|
2010-07-23 08:33:23 +08:00
|
|
|
|
|
|
|
// Create a file manager object to provide access to and cache the filesystem.
|
|
|
|
Clang.setFileManager(new FileManager);
|
|
|
|
|
|
|
|
// Create the source manager.
|
|
|
|
Clang.setSourceManager(new SourceManager(getDiagnostics()));
|
|
|
|
|
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();
|
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
delete NewPreamble.first;
|
2010-07-31 04:58:08 +08:00
|
|
|
if (PreambleTimer)
|
|
|
|
PreambleTimer->stopTimer();
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
|
2010-07-31 04:58:08 +08:00
|
|
|
|
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.
|
|
|
|
// FIXME: Should we leave a note for ourselves to try again?
|
|
|
|
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
|
|
|
|
Preamble.clear();
|
|
|
|
if (CreatedPreambleBuffer)
|
|
|
|
delete NewPreamble.first;
|
2010-07-31 04:58:08 +08:00
|
|
|
if (PreambleTimer)
|
|
|
|
PreambleTimer->stopTimer();
|
2010-08-04 03:06:41 +08:00
|
|
|
TopLevelDeclsInPreamble.clear();
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = DefaultPreambleRebuildInterval;
|
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-07-31 04:58:08 +08:00
|
|
|
if (PreambleTimer)
|
|
|
|
PreambleTimer->stopTimer();
|
|
|
|
|
2010-08-04 13:53:38 +08:00
|
|
|
PreambleRebuildCounter = 1;
|
2010-07-24 08:38:13 +08:00
|
|
|
return CreatePaddedMainFileBuffer(NewPreamble.first,
|
|
|
|
CreatedPreambleBuffer,
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ASTUnit::getMaxPCHLevel() const {
|
|
|
|
if (!getOnlyLocalDecls())
|
|
|
|
return Decl::MaxPCHLevel;
|
|
|
|
|
|
|
|
unsigned Result = 0;
|
|
|
|
if (isMainFileAST() || SavedMainFileBuffer)
|
|
|
|
++Result;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
bool CacheCodeCompletionResults) {
|
2010-07-20 05:46:24 +08:00
|
|
|
if (!Diags.getPtr()) {
|
|
|
|
// No diagnostics engine was provided, so create our own diagnostics object
|
|
|
|
// with the default options.
|
|
|
|
DiagnosticOptions DiagOpts;
|
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the AST unit.
|
|
|
|
llvm::OwningPtr<ASTUnit> AST;
|
|
|
|
AST.reset(new ASTUnit(false));
|
|
|
|
AST->Diagnostics = Diags;
|
|
|
|
AST->CaptureDiagnostics = CaptureDiagnostics;
|
|
|
|
AST->OnlyLocalDecls = OnlyLocalDecls;
|
2010-08-10 04:45:32 +08:00
|
|
|
AST->CompleteTranslationUnit = CompleteTranslationUnit;
|
2010-08-14 06:48:40 +08:00
|
|
|
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
|
2010-07-20 05:46:24 +08:00
|
|
|
AST->Invocation.reset(CI);
|
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
|
|
|
CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2010-07-31 04:58:08 +08:00
|
|
|
if (getenv("LIBCLANG_TIMING"))
|
|
|
|
AST->TimerGroup.reset(
|
|
|
|
new llvm::TimerGroup(CI->getFrontendOpts().Inputs[0].second));
|
|
|
|
|
|
|
|
|
2010-07-24 08:38:13 +08:00
|
|
|
llvm::MemoryBuffer *OverrideMainBuffer = 0;
|
2010-07-29 06:12:37 +08:00
|
|
|
// FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble.
|
2010-08-04 13:53:38 +08:00
|
|
|
if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus) {
|
|
|
|
AST->PreambleRebuildCounter = 1;
|
2010-08-10 04:45:32 +08:00
|
|
|
OverrideMainBuffer = AST->getMainBufferWithPrecompiledPreamble();
|
2010-08-04 13:53:38 +08:00
|
|
|
}
|
2010-07-23 08:33:23 +08:00
|
|
|
|
2010-07-31 04:58:08 +08:00
|
|
|
llvm::Timer *ParsingTimer = 0;
|
|
|
|
if (AST->TimerGroup.get()) {
|
|
|
|
ParsingTimer = new llvm::Timer("Initial parse", *AST->TimerGroup);
|
|
|
|
ParsingTimer->startTimer();
|
|
|
|
AST->Timers.push_back(ParsingTimer);
|
|
|
|
}
|
2010-07-20 05:46:24 +08:00
|
|
|
|
2010-07-31 04:58:08 +08:00
|
|
|
bool Failed = AST->Parse(OverrideMainBuffer);
|
|
|
|
if (ParsingTimer)
|
|
|
|
ParsingTimer->stopTimer();
|
|
|
|
|
|
|
|
return Failed? 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-01-23 08:14:00 +08:00
|
|
|
RemappedFile *RemappedFiles,
|
2010-02-19 02:08:43 +08:00
|
|
|
unsigned NumRemappedFiles,
|
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,
|
|
|
|
bool CacheCodeCompletionResults) {
|
2010-08-19 06:29:43 +08:00
|
|
|
bool CreatedDiagnosticsObject = false;
|
|
|
|
|
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;
|
2010-04-06 07:52:57 +08:00
|
|
|
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
2010-08-19 06:29:43 +08:00
|
|
|
CreatedDiagnosticsObject = true;
|
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");
|
|
|
|
|
2009-12-13 11:46:13 +08:00
|
|
|
// FIXME: We shouldn't have to pass in the path info.
|
2010-07-19 08:44:04 +08:00
|
|
|
driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
|
2010-04-06 05:10:19 +08:00
|
|
|
"a.out", false, false, *Diags);
|
2010-01-25 08:44:02 +08:00
|
|
|
|
|
|
|
// Don't check that inputs exist, they have been remapped.
|
|
|
|
TheDriver.setCheckInputsExist(false);
|
|
|
|
|
2009-12-02 11:23:45 +08:00
|
|
|
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);
|
2010-04-06 05:10:19 +08:00
|
|
|
Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
|
2009-12-02 11:23:45 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
|
|
|
|
if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
|
2010-04-06 05:10:19 +08:00
|
|
|
Diags->Report(diag::err_fe_expected_clang_command);
|
2009-12-02 11:23:45 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const driver::ArgStringList &CCArgs = Cmd->getArguments();
|
2010-01-31 05:47:16 +08:00
|
|
|
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
|
2010-04-20 00:39:44 +08:00
|
|
|
CompilerInvocation::CreateFromArgs(*CI,
|
|
|
|
const_cast<const char **>(CCArgs.data()),
|
|
|
|
const_cast<const char **>(CCArgs.data()) +
|
2010-07-23 08:33:23 +08:00
|
|
|
CCArgs.size(),
|
2010-04-06 05:10:19 +08:00
|
|
|
*Diags);
|
2009-12-13 11:45:58 +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-08-19 07:38:21 +08:00
|
|
|
CI->getFrontendOpts().DisableFree = false;
|
2010-02-19 02:08:43 +08:00
|
|
|
return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
|
2010-08-10 04:45:32 +08:00
|
|
|
CaptureDiagnostics, PrecompilePreamble,
|
2010-08-14 06:48:40 +08:00
|
|
|
CompleteTranslationUnit,
|
|
|
|
CacheCodeCompletionResults);
|
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-07-31 04:58:08 +08:00
|
|
|
llvm::Timer *ReparsingTimer = 0;
|
|
|
|
if (TimerGroup.get()) {
|
|
|
|
ReparsingTimer = new llvm::Timer("Reparse", *TimerGroup);
|
|
|
|
ReparsingTimer->startTimer();
|
|
|
|
Timers.push_back(ReparsingTimer);
|
|
|
|
}
|
|
|
|
|
2010-07-31 08:40:00 +08:00
|
|
|
// Remap files.
|
|
|
|
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-10 04:45:32 +08:00
|
|
|
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble();
|
2010-07-24 07:58:40 +08:00
|
|
|
|
2010-07-20 05:46:24 +08:00
|
|
|
// Clear out the diagnostics state.
|
2010-08-03 04:51:39 +08:00
|
|
|
if (!OverrideMainBuffer)
|
|
|
|
getDiagnostics().Reset();
|
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-31 04:58:08 +08:00
|
|
|
if (ReparsingTimer)
|
|
|
|
ReparsingTimer->stopTimer();
|
2010-08-17 08:40:40 +08:00
|
|
|
|
|
|
|
if (ShouldCacheCodeCompletionResults) {
|
|
|
|
if (CacheCodeCompletionCoolDown > 0)
|
|
|
|
--CacheCodeCompletionCoolDown;
|
|
|
|
else if (top_level_size() != NumTopLevelDeclsAtLastCompletionCache)
|
|
|
|
CacheCodeCompletionResults();
|
|
|
|
}
|
|
|
|
|
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))
|
|
|
|
| (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1));
|
|
|
|
|
|
|
|
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,
|
|
|
|
Result *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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
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.
|
|
|
|
void CalculateHiddenNames(const CodeCompletionContext &Context,
|
|
|
|
CodeCompleteConsumer::Result *Results,
|
|
|
|
unsigned NumResults,
|
|
|
|
ASTContext &Ctx,
|
|
|
|
llvm::StringSet<> &HiddenNames) {
|
|
|
|
bool OnlyTagNames = false;
|
|
|
|
switch (Context.getKind()) {
|
|
|
|
case CodeCompletionContext::CCC_Other:
|
|
|
|
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:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CodeCompletionContext::CCC_EnumTag:
|
|
|
|
case CodeCompletionContext::CCC_UnionTag:
|
|
|
|
case CodeCompletionContext::CCC_ClassOrStructTag:
|
|
|
|
OnlyTagNames = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CodeCompletionContext::CCC_ObjCProtocolName:
|
|
|
|
// If we're just looking for protocol names, nothing can hide them.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef CodeCompleteConsumer::Result Result;
|
|
|
|
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,
|
|
|
|
Result *Results,
|
|
|
|
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
|
|
|
|
= (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts
|
|
|
|
: (1 << (Context.getKind() - 1)));
|
|
|
|
|
|
|
|
// Contains the set of names that are hidden by "local" completion results.
|
|
|
|
llvm::StringSet<> HiddenNames;
|
|
|
|
|
2010-08-17 04:01:48 +08:00
|
|
|
typedef CodeCompleteConsumer::Result Result;
|
|
|
|
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;
|
|
|
|
if (!Context.getPreferredType().isNull()) {
|
|
|
|
if (C->Kind == CXCursor_MacroDefinition) {
|
|
|
|
Priority = getMacroUsagePriority(C->Completion->getTypedText(),
|
|
|
|
Context.getPreferredType()->isAnyPointerType());
|
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AllResults.push_back(Result(C->Completion, Priority, C->Kind));
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics) {
|
|
|
|
if (!Invocation.get())
|
|
|
|
return;
|
|
|
|
|
2010-08-10 04:45:32 +08:00
|
|
|
llvm::Timer *CompletionTimer = 0;
|
|
|
|
if (TimerGroup.get()) {
|
|
|
|
llvm::SmallString<128> TimerName;
|
|
|
|
llvm::raw_svector_ostream TimerNameOut(TimerName);
|
|
|
|
TimerNameOut << "Code completion @ " << File << ":" << Line << ":"
|
|
|
|
<< Column;
|
|
|
|
CompletionTimer = new llvm::Timer(TimerNameOut.str(), *TimerGroup);
|
|
|
|
CompletionTimer->startTimer();
|
|
|
|
Timers.push_back(CompletionTimer);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2010-08-05 17:09:23 +08:00
|
|
|
// Turn on spell-checking when performing code completion. It leads
|
|
|
|
// to better results.
|
|
|
|
unsigned SpellChecking = CCInvocation.getLangOpts().SpellChecking;
|
|
|
|
CCInvocation.getLangOpts().SpellChecking = 1;
|
|
|
|
|
2010-08-05 00:47:14 +08:00
|
|
|
// 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);
|
|
|
|
CaptureDroppedDiagnostics Capture(true,
|
|
|
|
Clang.getDiagnostics(),
|
|
|
|
StoredDiagnostics);
|
|
|
|
|
|
|
|
// Create the target instance.
|
|
|
|
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
|
|
|
Clang.getTargetOpts()));
|
|
|
|
if (!Clang.hasTarget()) {
|
|
|
|
Clang.takeInvocation();
|
2010-08-19 06:29:43 +08:00
|
|
|
CCInvocation.getLangOpts().SpellChecking = SpellChecking;
|
|
|
|
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-05 00:47:14 +08:00
|
|
|
for (unsigned I = 0; I != NumRemappedFiles; ++I)
|
|
|
|
PreprocessorOpts.addRemappedFile(RemappedFiles[I].first,
|
|
|
|
RemappedFiles[I].second);
|
|
|
|
|
2010-08-14 06:48:40 +08:00
|
|
|
// Use the code completion consumer we were given, but adding any cached
|
|
|
|
// code-completion results.
|
|
|
|
AugmentedCodeCompleteConsumer
|
|
|
|
AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion,
|
2010-08-15 14:18:01 +08:00
|
|
|
FrontendOpts.ShowCodePatternsInCodeCompletion,
|
|
|
|
FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
|
2010-08-14 06:48:40 +08:00
|
|
|
Clang.setCodeCompletionConsumer(&AugmentedConsumer);
|
2010-08-05 00:47:14 +08:00
|
|
|
|
2010-08-10 04:45:32 +08:00
|
|
|
// If we have a precompiled preamble, try to use it. We only allow
|
|
|
|
// the use of the precompiled preamble if we're if the completion
|
|
|
|
// point is within the main file, after the end of the precompiled
|
|
|
|
// preamble.
|
|
|
|
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())
|
|
|
|
OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(false,
|
|
|
|
Line);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the main file has been overridden due to the use of a preamble,
|
|
|
|
// make that override happen and introduce the preamble.
|
|
|
|
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.
|
|
|
|
for (unsigned I = 0, N = this->StoredDiagnostics.size(); I != N; ++I) {
|
|
|
|
StoredDiagnostics.push_back(this->StoredDiagnostics[I]);
|
|
|
|
FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr);
|
|
|
|
StoredDiagnostics[I].setLocation(Loc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
if (CompletionTimer)
|
|
|
|
CompletionTimer->stopTimer();
|
2010-08-05 00:47:14 +08:00
|
|
|
|
|
|
|
// Steal back our resources.
|
2010-08-10 04:45:32 +08:00
|
|
|
delete OverrideMainBuffer;
|
2010-08-05 00:47:14 +08:00
|
|
|
Clang.takeFileManager();
|
|
|
|
Clang.takeSourceManager();
|
|
|
|
Clang.takeInvocation();
|
|
|
|
Clang.takeCodeCompletionConsumer();
|
2010-08-05 17:09:23 +08:00
|
|
|
CCInvocation.getLangOpts().SpellChecking = SpellChecking;
|
2010-08-05 00:47:14 +08:00
|
|
|
}
|
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);
|
|
|
|
PCHWriter Writer(Stream);
|
|
|
|
Writer.WritePCH(getSema(), 0, 0);
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|