2019-09-04 15:35:00 +08:00
|
|
|
//===--- Preamble.h - Reusing expensive parts of the AST ---------*- C++-*-===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The vast majority of code in a typical translation unit is in the headers
|
|
|
|
// included at the top of the file.
|
|
|
|
//
|
|
|
|
// The preamble optimization says that we can parse this code once, and reuse
|
|
|
|
// the result multiple times. The preamble is invalidated by changes to the
|
|
|
|
// code in the preamble region, to the compile command, or to files on disk.
|
|
|
|
//
|
|
|
|
// This is the most important optimization in clangd: it allows operations like
|
|
|
|
// code-completion to have sub-second latency. It is supported by the
|
|
|
|
// PrecompiledPreamble functionality in clang, which wraps the techniques used
|
|
|
|
// by PCH files, modules etc into a convenient interface.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PREAMBLE_H
|
|
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PREAMBLE_H
|
|
|
|
|
2019-09-24 19:14:06 +08:00
|
|
|
#include "CollectMacros.h"
|
2019-09-04 15:35:00 +08:00
|
|
|
#include "Compiler.h"
|
|
|
|
#include "Diagnostics.h"
|
|
|
|
#include "FS.h"
|
|
|
|
#include "Headers.h"
|
|
|
|
#include "index/CanonicalIncludes.h"
|
[clangd] Move non-clang base pieces into separate support/ lib. NFCI
Summary:
This enforces layering, reduces a sprawling clangd/ directory, and makes life
easier for embedders.
Reviewers: kbobyrev
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D79014
2020-04-28 23:49:17 +08:00
|
|
|
#include "support/Path.h"
|
2020-03-16 04:43:00 +08:00
|
|
|
#include "clang/Frontend/CompilerInvocation.h"
|
2019-09-04 15:35:00 +08:00
|
|
|
#include "clang/Frontend/PrecompiledPreamble.h"
|
2020-06-17 03:21:45 +08:00
|
|
|
#include "clang/Lex/Lexer.h"
|
2019-09-04 15:35:00 +08:00
|
|
|
#include "clang/Tooling/CompilationDatabase.h"
|
2020-04-02 16:53:23 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2019-09-04 15:35:00 +08:00
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
|
|
|
|
/// The parsed preamble and associated data.
|
|
|
|
///
|
|
|
|
/// As we must avoid re-parsing the preamble, any information that can only
|
|
|
|
/// be obtained during parsing must be eagerly captured and stored here.
|
|
|
|
struct PreambleData {
|
2020-03-11 23:34:01 +08:00
|
|
|
PreambleData(const ParseInputs &Inputs, PrecompiledPreamble Preamble,
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
std::vector<Diag> Diags, IncludeStructure Includes,
|
|
|
|
MainFileMacros Macros,
|
2019-09-04 15:35:00 +08:00
|
|
|
std::unique_ptr<PreambleFileStatusCache> StatCache,
|
|
|
|
CanonicalIncludes CanonIncludes);
|
|
|
|
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
// Version of the ParseInputs this preamble was built from.
|
|
|
|
std::string Version;
|
2019-09-04 15:35:00 +08:00
|
|
|
tooling::CompileCommand CompileCommand;
|
|
|
|
PrecompiledPreamble Preamble;
|
|
|
|
std::vector<Diag> Diags;
|
|
|
|
// Processes like code completions and go-to-definitions will need #include
|
|
|
|
// information, and their compile action skips preamble range.
|
|
|
|
IncludeStructure Includes;
|
|
|
|
// Macros defined in the preamble section of the main file.
|
|
|
|
// Users care about headers vs main-file, not preamble vs non-preamble.
|
|
|
|
// These should be treated as main-file entities e.g. for code completion.
|
2019-09-24 19:14:06 +08:00
|
|
|
MainFileMacros Macros;
|
2019-09-04 15:35:00 +08:00
|
|
|
// Cache of FS operations performed when building the preamble.
|
|
|
|
// When reusing a preamble, this cache can be consumed to save IO.
|
|
|
|
std::unique_ptr<PreambleFileStatusCache> StatCache;
|
|
|
|
CanonicalIncludes CanonIncludes;
|
|
|
|
};
|
|
|
|
|
|
|
|
using PreambleParsedCallback =
|
|
|
|
std::function<void(ASTContext &, std::shared_ptr<clang::Preprocessor>,
|
|
|
|
const CanonicalIncludes &)>;
|
|
|
|
|
|
|
|
/// Build a preamble for the new inputs unless an old one can be reused.
|
|
|
|
/// If \p PreambleCallback is set, it will be run on top of the AST while
|
2020-03-16 04:43:00 +08:00
|
|
|
/// building the preamble.
|
2019-09-04 15:35:00 +08:00
|
|
|
std::shared_ptr<const PreambleData>
|
2020-03-13 18:52:19 +08:00
|
|
|
buildPreamble(PathRef FileName, CompilerInvocation CI,
|
2019-09-04 15:35:00 +08:00
|
|
|
const ParseInputs &Inputs, bool StoreInMemory,
|
|
|
|
PreambleParsedCallback PreambleCallback);
|
|
|
|
|
2020-03-16 04:43:00 +08:00
|
|
|
/// Returns true if \p Preamble is reusable for \p Inputs. Note that it will
|
|
|
|
/// return true when some missing headers are now available.
|
|
|
|
/// FIXME: Should return more information about the delta between \p Preamble
|
|
|
|
/// and \p Inputs, e.g. new headers.
|
|
|
|
bool isPreambleCompatible(const PreambleData &Preamble,
|
|
|
|
const ParseInputs &Inputs, PathRef FileName,
|
|
|
|
const CompilerInvocation &CI);
|
2020-04-02 16:53:23 +08:00
|
|
|
|
|
|
|
/// Stores information required to parse a TU using a (possibly stale) Baseline
|
2020-04-02 16:53:45 +08:00
|
|
|
/// preamble. Later on this information can be injected into the main file by
|
|
|
|
/// updating compiler invocation with \c apply. This injected section
|
|
|
|
/// approximately reflects additions to the preamble in Modified contents, e.g.
|
|
|
|
/// new include directives.
|
2020-04-02 16:53:23 +08:00
|
|
|
class PreamblePatch {
|
|
|
|
public:
|
2020-04-02 16:53:45 +08:00
|
|
|
/// \p Preamble is used verbatim.
|
|
|
|
static PreamblePatch unmodified(const PreambleData &Preamble);
|
2020-04-02 16:53:23 +08:00
|
|
|
/// Builds a patch that contains new PP directives introduced to the preamble
|
|
|
|
/// section of \p Modified compared to \p Baseline.
|
|
|
|
/// FIXME: This only handles include directives, we should at least handle
|
|
|
|
/// define/undef.
|
|
|
|
static PreamblePatch create(llvm::StringRef FileName,
|
|
|
|
const ParseInputs &Modified,
|
|
|
|
const PreambleData &Baseline);
|
|
|
|
/// Adjusts CI (which compiles the modified inputs) to be used with the
|
|
|
|
/// baseline preamble. This is done by inserting an artifical include to the
|
|
|
|
/// \p CI that contains new directives calculated in create.
|
|
|
|
void apply(CompilerInvocation &CI) const;
|
|
|
|
|
2020-04-02 16:53:45 +08:00
|
|
|
/// Returns #include directives from the \c Modified preamble that were
|
|
|
|
/// resolved using the \c Baseline preamble. This covers the new locations of
|
|
|
|
/// inclusions that were moved around, but not inclusions of new files. Those
|
|
|
|
/// will be recorded when parsing the main file: the includes in the injected
|
|
|
|
/// section will be resolved back to their spelled positions in the main file
|
|
|
|
/// using the presumed-location mechanism.
|
|
|
|
std::vector<Inclusion> preambleIncludes() const;
|
|
|
|
|
2020-06-17 03:21:45 +08:00
|
|
|
/// Returns preamble bounds for the Modified.
|
|
|
|
PreambleBounds modifiedBounds() const { return ModifiedBounds; }
|
|
|
|
|
2020-05-14 18:20:33 +08:00
|
|
|
/// Returns textual patch contents.
|
|
|
|
llvm::StringRef text() const { return PatchContents; }
|
|
|
|
|
2021-03-15 17:18:12 +08:00
|
|
|
/// Whether diagnostics generated using this patch are trustable.
|
|
|
|
bool preserveDiagnostics() const { return PatchContents.empty(); }
|
|
|
|
|
2020-04-02 16:53:23 +08:00
|
|
|
private:
|
2020-04-02 16:53:45 +08:00
|
|
|
PreamblePatch() = default;
|
2020-04-02 16:53:23 +08:00
|
|
|
std::string PatchContents;
|
|
|
|
std::string PatchFileName;
|
2020-04-02 16:53:45 +08:00
|
|
|
/// Includes that are present in both \p Baseline and \p Modified. Used for
|
|
|
|
/// patching includes of baseline preamble.
|
|
|
|
std::vector<Inclusion> PreambleIncludes;
|
2020-06-17 03:21:45 +08:00
|
|
|
PreambleBounds ModifiedBounds = {0, false};
|
2020-04-02 16:53:23 +08:00
|
|
|
};
|
|
|
|
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
/// Translates locations inside preamble patch to their main-file equivalent
|
|
|
|
/// using presumed locations. Returns \p Loc if it isn't inside preamble patch.
|
|
|
|
SourceLocation translatePreamblePatchLocation(SourceLocation Loc,
|
|
|
|
const SourceManager &SM);
|
|
|
|
|
2019-09-04 15:35:00 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|
|
|
|
|
|
|
|
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_PREAMBLE_H
|