[clang-tools-extra] r308738 - [clangd] Replace ASTUnit with manual AST management.
Yung, Douglas via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 24 12:08:10 PDT 2017
Hi Ilya,
Your change seems to be causing the test 'clangd/definitions.test' to fail on the PS4 Windows bot. Can you take a look?
http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/11222
FAIL: Clang Tools :: clangd/definitions.test (11935 of 34225)
******************** TEST 'Clang Tools :: clangd/definitions.test' FAILED ********************
Script:
--
clangd -run-synchronously < C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\tools\clang\tools\extra\test\clangd\definitions.test | FileCheck C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\tools\clang\tools\extra\test\clangd\definitions.test
--
Exit Code: 1
Command Output (stdout):
--
$ "clangd" "-run-synchronously"
# command stderr:
<-- {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
--> {"jsonrpc":"2.0","id":0,"result":{"capabilities":{
"textDocumentSync": 1,
"documentFormattingProvider": true,
"documentRangeFormattingProvider": true,
"documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
"codeActionProvider": true,
"completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]},
"definitionProvider": true
}}}
<-- {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"int main() {\nint a;\na;\n}\n"}}}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[{"range":{"start": {"line": 2, "character": 1}, "end": {"line": 2, "character": 1}},"severity":2,"message":"expression result unused"}]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":0}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":1}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":2},"contentChanges":[{"text":"struct Foo {\nint x;\n};\nint main() {\n Foo bar = { x : 1 };\n}\n"}]}}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[{"range":{"start": {"line": 4, "character": 15}, "end": {"line": 4, "character": 15}},"severity":2,"message":"use of GNU old-style field designator extension"}]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":14}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":3},"contentChanges":[{"text":"struct Foo {\nint x;\n};\nint main() {\n Foo baz = { .x = 2 };\n}\n"}]}}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":15}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":4},"contentChanges":[{"text":"int main() {\n main();\n return 0;\n}"}]}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":3}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3, "character": 1}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"struct Foo {\n};\nint main() {\n Foo bar;\n return 0;\n}\n"}]}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":3}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 1, "character": 1}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"namespace n1 {\nstruct Foo {\n};\n}\nint main() {\n n1::Foo bar;\n return 0;\n}\n"}]}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":4}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3, "character": 1}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":6},"contentChanges":[{"text":"struct Foo {\n int x;\n};\nint main() {\n Foo bar;\n bar.x;\n}\n"}]}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[{"range":{"start": {"line": 5, "character": 8}, "end": {"line": 5, "character": 8}},"severity":2,"message":"expression result unused"}]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":7}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 1, "character": 7}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n void x();\n};\nint main() {\n Foo bar;\n bar.x();\n}\n"}]}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":7}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 1, "character": 10}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n};\ntypedef Foo TypedefFoo;\nint main() {\n TypedefFoo bar;\n return 0;\n}\n"}]}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":10}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 22}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"template <typename MyTemplateParam>\nvoid foo() {\n MyTemplateParam a;\n}\nint main() {\n return 0;\n}\n"}]}}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":13}}}
--> {"jsonrpc":"2.0","id":1,"result":[]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\nstatic void bar() {}\n};\n}\nint main() {\n ns::Foo::bar();\n return 0;\n}\n"}]}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":6,"character":4}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 4, "character": 1}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\n int field;\n Foo(int param) : field(param) {}\n};\n}\nint main() {\n return 0;\n}\n"}]}}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":21}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 2}, "end": {"line": 2, "character": 11}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"#define MY_MACRO 0\nint main() {\n return MY_MACRO;\n}\n"}]}}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":9}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///C:/main.cpp", "range": {"start": {"line": 0, "character": 8}, "end": {"line": 0, "character": 18}}}]}
<-- {"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"#define FOO 1\nint a = FOO;\n#define FOO 2\nint b = FOO;\n#undef FOO\n"}]}}
--> {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///main.cpp","diagnostics":[{"range":{"start": {"line": 2, "character": 9}, "end": {"line": 2, "character": 9}},"severity":2,"message":"'FOO' macro redefined"}]}}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":8}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///C:/main.cpp", "range": {"start": {"line": 0, "character": 8}, "end": {"line": 0, "character": 13}}}]}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":8}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2, "character": 13}}}]}
<-- {"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":7}}}
--> {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2, "character": 13}}}]}
<-- {"jsonrpc":"2.0","id":3,"method":"shutdown"}
$ "FileCheck" "C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\tools\clang\tools\extra\test\clangd\definitions.test"
# command stderr:
C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\tools\clang\tools\extra\test\clangd\definitions.test:142:10: error: expected string not found in input
# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 8}, "end": {"line": 0, "character": 18}}}]}
^
<stdin>:61:150: note: scanning from here
{"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 2}, "end": {"line": 2, "character": 11}}}]}Content-Length: 113
^
<stdin>:71:1: note: possible intended match here
{"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2, "character": 13}}}]}Content-Length: 149
^
error: command failed with exit status: 1
--
********************
> -----Original Message-----
> From: cfe-commits [mailto:cfe-commits-bounces at lists.llvm.org] On Behalf Of
> Ilya Biryukov via cfe-commits
> Sent: Friday, July 21, 2017 6:29
> To: cfe-commits at lists.llvm.org
> Subject: [clang-tools-extra] r308738 - [clangd] Replace ASTUnit with manual
> AST management.
>
> Author: ibiryukov
> Date: Fri Jul 21 06:29:29 2017
> New Revision: 308738
>
> URL: http://llvm.org/viewvc/llvm-project?rev=308738&view=rev
> Log:
> [clangd] Replace ASTUnit with manual AST management.
>
> Summary:
> This refactoring does not aim to introduce any significant changes to the
> behaviour of clangd to keep the change as simple as possible.
>
> Reviewers: klimek, krasimir, bkramer
>
> Reviewed By: krasimir
>
> Subscribers: malaperle, cfe-commits
>
> Tags: #clang-tools-extra
>
> Differential Revision: https://reviews.llvm.org/D35406
>
> Modified:
> clang-tools-extra/trunk/clangd/ClangdServer.cpp
> clang-tools-extra/trunk/clangd/ClangdUnit.cpp
> clang-tools-extra/trunk/clangd/ClangdUnit.h
>
> Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-
> extra/trunk/clangd/ClangdServer.cpp?rev=308738&r1=308737&r2=308738&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Fri Jul 21 06:29:29
> +++ 2017
> @@ -205,14 +205,11 @@ ClangdServer::codeComplete(PathRef File,
>
> std::vector<CompletionItem> Result;
> auto TaggedFS = FSProvider.getTaggedFileSystem(File);
> - // It would be nice to use runOnUnitWithoutReparse here, but we can't
> - // guarantee the correctness of code completion cache here if we don't do
> the
> - // reparse.
> - Units.runOnUnit(File, *OverridenContents, ResourceDir, CDB, PCHs,
> - TaggedFS.Value, [&](ClangdUnit &Unit) {
> - Result = Unit.codeComplete(*OverridenContents, Pos,
> - TaggedFS.Value);
> - });
> + Units.runOnUnitWithoutReparse(File, *OverridenContents, ResourceDir, CDB,
> + PCHs, TaggedFS.Value, [&](ClangdUnit &Unit) {
> + Result = Unit.codeComplete(
> + *OverridenContents, Pos,
> TaggedFS.Value);
> + });
> return make_tagged(std::move(Result), TaggedFS.Tag); }
>
>
> Modified: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-
> extra/trunk/clangd/ClangdUnit.cpp?rev=308738&r1=308737&r2=308738&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdUnit.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp Fri Jul 21 06:29:29
> +++ 2017
> @@ -9,16 +9,22 @@
>
> #include "ClangdUnit.h"
>
> -#include "clang/Frontend/ASTUnit.h"
> #include "clang/Frontend/CompilerInstance.h"
> #include "clang/Frontend/CompilerInvocation.h"
> +#include "clang/Frontend/FrontendActions.h"
> #include "clang/Frontend/Utils.h"
> -#include "clang/Index/IndexingAction.h"
> #include "clang/Index/IndexDataConsumer.h"
> +#include "clang/Index/IndexingAction.h"
> #include "clang/Lex/Lexer.h"
> #include "clang/Lex/MacroInfo.h"
> #include "clang/Lex/Preprocessor.h"
> +#include "clang/Lex/PreprocessorOptions.h"
> +#include "clang/Sema/Sema.h"
> +#include "clang/Serialization/ASTWriter.h"
> #include "clang/Tooling/CompilationDatabase.h"
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/Support/CrashRecoveryContext.h"
> #include "llvm/Support/Format.h"
>
> #include <algorithm>
> @@ -26,6 +32,196 @@
> using namespace clang::clangd;
> using namespace clang;
>
> +namespace {
> +
> +class DeclTrackingASTConsumer : public ASTConsumer {
> +public:
> + DeclTrackingASTConsumer(std::vector<const Decl *> &TopLevelDecls)
> + : TopLevelDecls(TopLevelDecls) {}
> +
> + bool HandleTopLevelDecl(DeclGroupRef DG) override {
> + for (const Decl *D : DG) {
> + // ObjCMethodDecl are not actually top-level decls.
> + if (isa<ObjCMethodDecl>(D))
> + continue;
> +
> + TopLevelDecls.push_back(D);
> + }
> + return true;
> + }
> +
> +private:
> + std::vector<const Decl *> &TopLevelDecls; };
> +
> +class ClangdFrontendAction : public SyntaxOnlyAction {
> +public:
> + std::vector<const Decl *> takeTopLevelDecls() {
> + return std::move(TopLevelDecls);
> + }
> +
> +protected:
> + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
> + StringRef InFile) override {
> + return llvm::make_unique<DeclTrackingASTConsumer>(/*ref*/
> +TopLevelDecls);
> + }
> +
> +private:
> + std::vector<const Decl *> TopLevelDecls; };
> +
> +class ClangdUnitPreambleCallbacks : public PreambleCallbacks {
> +public:
> + std::vector<serialization::DeclID> takeTopLevelDeclIDs() {
> + return std::move(TopLevelDeclIDs);
> + }
> +
> + void AfterPCHEmitted(ASTWriter &Writer) override {
> + TopLevelDeclIDs.reserve(TopLevelDecls.size());
> + for (Decl *D : TopLevelDecls) {
> + // Invalid top-level decls may not have been serialized.
> + if (D->isInvalidDecl())
> + continue;
> + TopLevelDeclIDs.push_back(Writer.getDeclID(D));
> + }
> + }
> +
> + void HandleTopLevelDecl(DeclGroupRef DG) override {
> + for (Decl *D : DG) {
> + if (isa<ObjCMethodDecl>(D))
> + continue;
> + TopLevelDecls.push_back(D);
> + }
> + }
> +
> +private:
> + std::vector<Decl *> TopLevelDecls;
> + std::vector<serialization::DeclID> TopLevelDeclIDs; };
> +
> +/// Convert from clang diagnostic level to LSP severity.
> +static int getSeverity(DiagnosticsEngine::Level L) {
> + switch (L) {
> + case DiagnosticsEngine::Remark:
> + return 4;
> + case DiagnosticsEngine::Note:
> + return 3;
> + case DiagnosticsEngine::Warning:
> + return 2;
> + case DiagnosticsEngine::Fatal:
> + case DiagnosticsEngine::Error:
> + return 1;
> + case DiagnosticsEngine::Ignored:
> + return 0;
> + }
> + llvm_unreachable("Unknown diagnostic level!"); }
> +
> +llvm::Optional<DiagWithFixIts> toClangdDiag(StoredDiagnostic D) {
> + auto Location = D.getLocation();
> + if (!Location.isValid() || !Location.getManager().isInMainFile(Location))
> + return llvm::None;
> +
> + Position P;
> + P.line = Location.getSpellingLineNumber() - 1; P.character =
> + Location.getSpellingColumnNumber();
> + Range R = {P, P};
> + clangd::Diagnostic Diag = {R, getSeverity(D.getLevel()),
> + D.getMessage()};
> +
> + llvm::SmallVector<tooling::Replacement, 1> FixItsForDiagnostic;
> + for (const FixItHint &Fix : D.getFixIts()) {
> + FixItsForDiagnostic.push_back(clang::tooling::Replacement(
> + Location.getManager(), Fix.RemoveRange, Fix.CodeToInsert));
> + }
> + return DiagWithFixIts{Diag, std::move(FixItsForDiagnostic)}; }
> +
> +class StoreDiagsConsumer : public DiagnosticConsumer {
> +public:
> + StoreDiagsConsumer(std::vector<DiagWithFixIts> &Output) :
> +Output(Output) {}
> +
> + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
> + const clang::Diagnostic &Info) override {
> + DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
> +
> + if (auto convertedDiag = toClangdDiag(StoredDiagnostic(DiagLevel, Info)))
> + Output.push_back(std::move(*convertedDiag));
> + }
> +
> +private:
> + std::vector<DiagWithFixIts> &Output;
> +};
> +
> +class EmptyDiagsConsumer : public DiagnosticConsumer {
> +public:
> + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
> + const clang::Diagnostic &Info) override {} };
> +
> +std::unique_ptr<CompilerInvocation>
> +createCompilerInvocation(ArrayRef<const char *> ArgList,
> + IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
> + IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
> + auto CI = createInvocationFromCommandLine(ArgList, std::move(Diags),
> + std::move(VFS));
> + // We rely on CompilerInstance to manage the resource (i.e. free them
> +on
> + // EndSourceFile), but that won't happen if DisableFree is set to true.
> + // Since createInvocationFromCommandLine sets it to true, we have to
> +override
> + // it.
> + CI->getFrontendOpts().DisableFree = false;
> + return CI;
> +}
> +
> +/// Creates a CompilerInstance from \p CI, with main buffer overriden
> +to \p /// Buffer and arguments to read the PCH from \p Preamble, if \p
> +Preamble is not /// null. Note that vfs::FileSystem inside returned
> +instance may differ from \p /// VFS if additional file remapping were set in
> command-line arguments.
> +/// On some errors, returns null. When non-null value is returned, it's
> +expected /// to be consumed by the FrontendAction as it will have a
> +pointer to the \p /// Buffer that will only be deleted if BeginSourceFile is
> called.
> +std::unique_ptr<CompilerInstance>
> +prepareCompilerInstance(std::unique_ptr<clang::CompilerInvocation> CI,
> + const PrecompiledPreamble *Preamble,
> + std::unique_ptr<llvm::MemoryBuffer> Buffer,
> + std::shared_ptr<PCHContainerOperations> PCHs,
> + IntrusiveRefCntPtr<vfs::FileSystem> VFS,
> + DiagnosticConsumer &DiagsClient) {
> + assert(VFS && "VFS is null");
> + assert(!CI->getPreprocessorOpts().RetainRemappedFileBuffers &&
> + "Setting RetainRemappedFileBuffers to true will cause a memory leak
> "
> + "of ContentsBuffer");
> +
> + // NOTE: we use Buffer.get() when adding remapped files, so we have
> + to make // sure it will be released if no error is emitted.
> + if (Preamble) {
> + Preamble->AddImplicitPreamble(*CI, Buffer.get()); } else {
> + CI->getPreprocessorOpts().addRemappedFile(
> + CI->getFrontendOpts().Inputs[0].getFile(), Buffer.get()); }
> +
> + auto Clang = llvm::make_unique<CompilerInstance>(PCHs);
> + Clang->setInvocation(std::move(CI));
> + Clang->createDiagnostics(&DiagsClient, false);
> +
> + if (auto VFSWithRemapping = createVFSFromCompilerInvocation(
> + Clang->getInvocation(), Clang->getDiagnostics(), VFS))
> + VFS = VFSWithRemapping;
> + Clang->setVirtualFileSystem(VFS);
> +
> + Clang->setTarget(TargetInfo::CreateTargetInfo(
> + Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
> + if (!Clang->hasTarget())
> + return nullptr;
> +
> + // RemappedFileBuffers will handle the lifetime of the Buffer
> +pointer,
> + // release it.
> + Buffer.release();
> + return Clang;
> +}
> +
> +} // namespace
> +
> ClangdUnit::ClangdUnit(PathRef FileName, StringRef Contents,
> StringRef ResourceDir,
> std::shared_ptr<PCHContainerOperations> PCHs, @@ -
> 39,44 +235,54 @@ ClangdUnit::ClangdUnit(PathRef FileName,
> Commands.front().CommandLine.push_back("-resource-dir=" +
> std::string(ResourceDir));
>
> - IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
> - CompilerInstance::createDiagnostics(new DiagnosticOptions);
> -
> - std::vector<const char *> ArgStrs;
> - for (const auto &S : Commands.front().CommandLine)
> - ArgStrs.push_back(S.c_str());
> -
> - ASTUnit::RemappedFile RemappedSource(
> - FileName,
> - llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());
> -
> - auto ArgP = &*ArgStrs.begin();
> - Unit = std::unique_ptr<ASTUnit>(ASTUnit::LoadFromCommandLine(
> - ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,
> - /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true, RemappedSource,
> - /*RemappedFilesKeepOriginalName=*/true,
> - /*PrecompilePreambleAfterNParses=*/1, /*TUKind=*/TU_Prefix,
> - /*CacheCodeCompletionResults=*/true,
> - /*IncludeBriefCommentsInCodeCompletion=*/true,
> - /*AllowPCHWithCompilerErrors=*/true,
> - /*SkipFunctionBodies=*/false,
> - /*SingleFileParse=*/false,
> - /*UserFilesAreVolatile=*/false, /*ForSerialization=*/false,
> - /*ModuleFormat=*/llvm::None,
> - /*ErrAST=*/nullptr, VFS));
> - assert(Unit && "Unit wasn't created");
> + Command = std::move(Commands.front()); reparse(Contents, VFS);
> }
>
> void ClangdUnit::reparse(StringRef Contents,
> IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
> - // Do a reparse if this wasn't the first parse.
> - // FIXME: This might have the wrong working directory if it changed in the
> - // meantime.
> - ASTUnit::RemappedFile RemappedSource(
> - FileName,
> - llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());
> + std::vector<const char *> ArgStrs;
> + for (const auto &S : Command.CommandLine)
> + ArgStrs.push_back(S.c_str());
>
> - Unit->Reparse(PCHs, RemappedSource, VFS);
> + std::unique_ptr<CompilerInvocation> CI;
> + {
> + // FIXME(ibiryukov): store diagnostics from CommandLine when we start
> + // reporting them.
> + EmptyDiagsConsumer CommandLineDiagsConsumer;
> + IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
> + CompilerInstance::createDiagnostics(new DiagnosticOptions,
> + &CommandLineDiagsConsumer,
> false);
> + CI = createCompilerInvocation(ArgStrs, CommandLineDiagsEngine, VFS);
> + }
> + assert(CI && "Couldn't create CompilerInvocation");
> +
> + std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
> + llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName);
> +
> + // Rebuild the preamble if it is missing or can not be reused.
> + auto Bounds =
> + ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
> + if (!Preamble || !Preamble->Preamble.CanReuse(*CI, ContentsBuffer.get(),
> + Bounds, VFS.get())) {
> + std::vector<DiagWithFixIts> PreambleDiags;
> + StoreDiagsConsumer PreambleDiagnosticsConsumer(/*ref*/ PreambleDiags);
> + IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
> + CompilerInstance::createDiagnostics(
> + &CI->getDiagnosticOpts(), &PreambleDiagnosticsConsumer, false);
> + ClangdUnitPreambleCallbacks SerializedDeclsCollector;
> + auto BuiltPreamble = PrecompiledPreamble::Build(
> + *CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, VFS, PCHs,
> + SerializedDeclsCollector);
> + if (BuiltPreamble)
> + Preamble = PreambleData(std::move(*BuiltPreamble),
> + SerializedDeclsCollector.takeTopLevelDeclIDs(),
> + std::move(PreambleDiags));
> + }
> + Unit = ParsedAST::Build(
> + std::move(CI), Preamble ? &Preamble->Preamble : nullptr,
> + Preamble ? llvm::makeArrayRef(Preamble->TopLevelDeclIDs) : llvm::None,
> + std::move(ContentsBuffer), PCHs, VFS);
> }
>
> namespace {
> @@ -188,97 +394,164 @@ public:
> std::vector<CompletionItem>
> ClangdUnit::codeComplete(StringRef Contents, Position Pos,
> IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
> - CodeCompleteOptions CCO;
> - CCO.IncludeBriefComments = 1;
> - // This is where code completion stores dirty buffers. Need to free after
> - // completion.
> - SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;
> - SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
> - IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
> - new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));
> - std::vector<CompletionItem> Items;
> - CompletionItemsCollector Collector(&Items, CCO);
> + std::vector<const char *> ArgStrs;
> + for (const auto &S : Command.CommandLine)
> + ArgStrs.push_back(S.c_str());
>
> - ASTUnit::RemappedFile RemappedSource(
> - FileName,
> - llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());
> -
> - IntrusiveRefCntPtr<FileManager> FileMgr(
> - new FileManager(Unit->getFileSystemOpts(), VFS));
> - IntrusiveRefCntPtr<SourceManager> SourceMgr(
> - new SourceManager(*DiagEngine, *FileMgr));
> - // CodeComplete seems to require fresh LangOptions.
> - LangOptions LangOpts = Unit->getLangOpts();
> - // The language server protocol uses zero-based line and column numbers.
> - // The clang code completion uses one-based numbers.
> - Unit->CodeComplete(FileName, Pos.line + 1, Pos.character + 1,
> RemappedSource,
> - CCO.IncludeMacros, CCO.IncludeCodePatterns,
> - CCO.IncludeBriefComments, Collector, PCHs, *DiagEngine,
> - LangOpts, *SourceMgr, *FileMgr, StoredDiagnostics,
> - OwnedBuffers);
> - for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)
> - delete Buffer;
> - return Items;
> -}
> + std::unique_ptr<CompilerInvocation> CI;
> + EmptyDiagsConsumer DummyDiagsConsumer;
> + {
> + IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
> + CompilerInstance::createDiagnostics(new DiagnosticOptions,
> + &DummyDiagsConsumer, false);
> + CI = createCompilerInvocation(ArgStrs, CommandLineDiagsEngine, VFS);
> + }
> + assert(CI && "Couldn't create CompilerInvocation");
> +
> + std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
> + llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName);
> +
> + // Attempt to reuse the PCH from precompiled preamble, if it was built.
> + const PrecompiledPreamble *PreambleForCompletion = nullptr;
> + if (Preamble) {
> + auto Bounds =
> + ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
> + if (Preamble->Preamble.CanReuse(*CI, ContentsBuffer.get(), Bounds,
> + VFS.get()))
> + PreambleForCompletion = &Preamble->Preamble;
> + }
> +
> + auto Clang = prepareCompilerInstance(std::move(CI), PreambleForCompletion,
> + std::move(ContentsBuffer), PCHs, VFS,
> + DummyDiagsConsumer);
> + auto &DiagOpts = Clang->getDiagnosticOpts();
> + DiagOpts.IgnoreWarnings = true;
> +
> + auto &FrontendOpts = Clang->getFrontendOpts();
> + FrontendOpts.SkipFunctionBodies = true;
> +
> + FrontendOpts.CodeCompleteOpts.IncludeGlobals = true;
> + // we don't handle code patterns properly yet, disable them.
> + FrontendOpts.CodeCompleteOpts.IncludeCodePatterns = false;
> + FrontendOpts.CodeCompleteOpts.IncludeMacros = true;
> + FrontendOpts.CodeCompleteOpts.IncludeBriefComments = true;
> +
> + FrontendOpts.CodeCompletionAt.FileName = FileName;
> + FrontendOpts.CodeCompletionAt.Line = Pos.line + 1;
> + FrontendOpts.CodeCompletionAt.Column = Pos.character + 1;
>
> -namespace {
> -/// Convert from clang diagnostic level to LSP severity.
> -static int getSeverity(DiagnosticsEngine::Level L) {
> - switch (L) {
> - case DiagnosticsEngine::Remark:
> - return 4;
> - case DiagnosticsEngine::Note:
> - return 3;
> - case DiagnosticsEngine::Warning:
> - return 2;
> - case DiagnosticsEngine::Fatal:
> - case DiagnosticsEngine::Error:
> - return 1;
> - case DiagnosticsEngine::Ignored:
> - return 0;
> + std::vector<CompletionItem> Items;
> + Clang->setCodeCompletionConsumer(
> + new CompletionItemsCollector(&Items, FrontendOpts.CodeCompleteOpts));
> +
> + SyntaxOnlyAction Action;
> + if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
> + // FIXME(ibiryukov): log errors
> + return Items;
> }
> - llvm_unreachable("Unknown diagnostic level!");
> + if (!Action.Execute()) {
> + // FIXME(ibiryukov): log errors
> + }
> + Action.EndSourceFile();
> +
> + return Items;
> }
> -} // namespace
>
> std::vector<DiagWithFixIts> ClangdUnit::getLocalDiagnostics() const {
> + if (!Unit)
> + return {}; // Parsing failed.
> +
> std::vector<DiagWithFixIts> Result;
> - for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
> - DEnd = Unit->stored_diag_end();
> - D != DEnd; ++D) {
> - if (!D->getLocation().isValid() ||
> - !D->getLocation().getManager().isInMainFile(D->getLocation()))
> - continue;
> - Position P;
> - P.line = D->getLocation().getSpellingLineNumber() - 1;
> - P.character = D->getLocation().getSpellingColumnNumber();
> - Range R = {P, P};
> - clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D-
> >getMessage()};
> -
> - llvm::SmallVector<tooling::Replacement, 1> FixItsForDiagnostic;
> - for (const FixItHint &Fix : D->getFixIts()) {
> - FixItsForDiagnostic.push_back(clang::tooling::Replacement(
> - Unit->getSourceManager(), Fix.RemoveRange, Fix.CodeToInsert));
> - }
> - Result.push_back({Diag, std::move(FixItsForDiagnostic)});
> - }
> + auto PreambleDiagsSize = Preamble ? Preamble->Diags.size() : 0;
> + const auto &Diags = Unit->getDiagnostics();
> + Result.reserve(PreambleDiagsSize + Diags.size());
> +
> + if (Preamble)
> + Result.insert(Result.end(), Preamble->Diags.begin(), Preamble-
> >Diags.end());
> + Result.insert(Result.end(), Diags.begin(), Diags.end());
> return Result;
> }
>
> void ClangdUnit::dumpAST(llvm::raw_ostream &OS) const {
> + if (!Unit) {
> + OS << "<no-ast-in-clang>";
> + return; // Parsing failed.
> + }
> Unit->getASTContext().getTranslationUnitDecl()->dump(OS, true);
> }
>
> +llvm::Optional<ClangdUnit::ParsedAST>
> +ClangdUnit::ParsedAST::Build(std::unique_ptr<clang::CompilerInvocation> CI,
> + const PrecompiledPreamble *Preamble,
> + ArrayRef<serialization::DeclID> PreambleDeclIDs,
> + std::unique_ptr<llvm::MemoryBuffer> Buffer,
> + std::shared_ptr<PCHContainerOperations> PCHs,
> + IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
> +
> + std::vector<DiagWithFixIts> ASTDiags;
> + StoreDiagsConsumer UnitDiagsConsumer(/*ref*/ ASTDiags);
> +
> + auto Clang =
> + prepareCompilerInstance(std::move(CI), Preamble, std::move(Buffer),
> PCHs,
> + VFS, /*ref*/ UnitDiagsConsumer);
> +
> + // Recover resources if we crash before exiting this method.
> + llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
> + Clang.get());
> +
> + auto Action = llvm::make_unique<ClangdFrontendAction>();
> + if (!Action->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
> + // FIXME(ibiryukov): log error
> + return llvm::None;
> + }
> + if (!Action->Execute()) {
> + // FIXME(ibiryukov): log error
> + }
> +
> + // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
> + // has a longer lifetime.
> + Clang->getDiagnostics().setClient(new EmptyDiagsConsumer);
> +
> + std::vector<const Decl *> ParsedDecls = Action->takeTopLevelDecls();
> + std::vector<serialization::DeclID> PendingDecls;
> + if (Preamble) {
> + PendingDecls.reserve(PreambleDeclIDs.size());
> + PendingDecls.insert(PendingDecls.begin(), PreambleDeclIDs.begin(),
> + PreambleDeclIDs.end());
> + }
> +
> + return ParsedAST(std::move(Clang), std::move(Action),
> std::move(ParsedDecls),
> + std::move(PendingDecls), std::move(ASTDiags));
> +}
> +
> namespace {
> +
> +SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
> + const FileEntry *FE,
> + unsigned Offset) {
> + SourceLocation FileLoc = Mgr.translateFileLineCol(FE, 1, 1);
> + return Mgr.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset));
> +}
> +
> +SourceLocation getMacroArgExpandedLocation(const SourceManager &Mgr,
> + const FileEntry *FE, Position Pos)
> {
> + SourceLocation InputLoc =
> + Mgr.translateFileLineCol(FE, Pos.line + 1, Pos.character + 1);
> + return Mgr.getMacroArgExpandedLocation(InputLoc);
> +}
> +
> /// Finds declarations locations that a given source location refers to.
> class DeclarationLocationsFinder : public index::IndexDataConsumer {
> std::vector<Location> DeclarationLocations;
> const SourceLocation &SearchedLocation;
> - ASTUnit &Unit;
> + const ASTContext &AST;
> + Preprocessor &PP;
> +
> public:
> DeclarationLocationsFinder(raw_ostream &OS,
> - const SourceLocation &SearchedLocation, ASTUnit &Unit) :
> - SearchedLocation(SearchedLocation), Unit(Unit) {}
> + const SourceLocation &SearchedLocation,
> + ASTContext &AST, Preprocessor &PP)
> + : SearchedLocation(SearchedLocation), AST(AST), PP(PP) {}
>
> std::vector<Location> takeLocations() {
> // Don't keep the same location multiple times.
> @@ -302,17 +575,17 @@ public:
>
> private:
> bool isSearchedLocation(FileID FID, unsigned Offset) const {
> - const SourceManager &SourceMgr = Unit.getSourceManager();
> - return SourceMgr.getFileOffset(SearchedLocation) == Offset
> - && SourceMgr.getFileID(SearchedLocation) == FID;
> + const SourceManager &SourceMgr = AST.getSourceManager();
> + return SourceMgr.getFileOffset(SearchedLocation) == Offset &&
> + SourceMgr.getFileID(SearchedLocation) == FID;
> }
>
> - void addDeclarationLocation(const SourceRange& ValSourceRange) {
> - const SourceManager& SourceMgr = Unit.getSourceManager();
> - const LangOptions& LangOpts = Unit.getLangOpts();
> + void addDeclarationLocation(const SourceRange &ValSourceRange) {
> + const SourceManager &SourceMgr = AST.getSourceManager();
> + const LangOptions &LangOpts = AST.getLangOpts();
> SourceLocation LocStart = ValSourceRange.getBegin();
> SourceLocation LocEnd =
> Lexer::getLocForEndOfToken(ValSourceRange.getEnd(),
> - 0, SourceMgr, LangOpts);
> + 0, SourceMgr,
> LangOpts);
> Position Begin;
> Begin.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
> Begin.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
> @@ -330,24 +603,24 @@ private:
> void finish() override {
> // Also handle possible macro at the searched location.
> Token Result;
> - if (!Lexer::getRawToken(SearchedLocation, Result,
> Unit.getSourceManager(),
> - Unit.getASTContext().getLangOpts(), false)) {
> + if (!Lexer::getRawToken(SearchedLocation, Result, AST.getSourceManager(),
> + AST.getLangOpts(), false)) {
> if (Result.is(tok::raw_identifier)) {
> - Unit.getPreprocessor().LookUpIdentifierInfo(Result);
> + PP.LookUpIdentifierInfo(Result);
> }
> - IdentifierInfo* IdentifierInfo = Result.getIdentifierInfo();
> + IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
> if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
> std::pair<FileID, unsigned int> DecLoc =
> -
> Unit.getSourceManager().getDecomposedExpansionLoc(SearchedLocation);
> +
> AST.getSourceManager().getDecomposedExpansionLoc(SearchedLocation);
> // Get the definition just before the searched location so that a
> macro
> // referenced in a '#undef MACRO' can still be found.
> - SourceLocation BeforeSearchedLocation = Unit.getLocation(
> - Unit.getSourceManager().getFileEntryForID(DecLoc.first),
> + SourceLocation BeforeSearchedLocation = getMacroArgExpandedLocation(
> + AST.getSourceManager(),
> + AST.getSourceManager().getFileEntryForID(DecLoc.first),
> DecLoc.second - 1);
> MacroDefinition MacroDef =
> - Unit.getPreprocessor().getMacroDefinitionAtLoc(IdentifierInfo,
> - BeforeSearchedLocation);
> - MacroInfo* MacroInf = MacroDef.getMacroInfo();
> + PP.getMacroDefinitionAtLoc(IdentifierInfo,
> BeforeSearchedLocation);
> + MacroInfo *MacroInf = MacroDef.getMacroInfo();
> if (MacroInf) {
> addDeclarationLocation(
> SourceRange(MacroInf->getDefinitionLoc(),
> @@ -360,30 +633,41 @@ private:
> } // namespace
>
> std::vector<Location> ClangdUnit::findDefinitions(Position Pos) {
> - const FileEntry *FE = Unit->getFileManager().getFile(Unit-
> >getMainFileName());
> + if (!Unit)
> + return {}; // Parsing failed.
> +
> + const SourceManager &SourceMgr = Unit->getASTContext().getSourceManager();
> + const FileEntry *FE =
> SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
> if (!FE)
> return {};
>
> SourceLocation SourceLocationBeg = getBeginningOfIdentifier(Pos, FE);
>
> auto DeclLocationsFinder = std::make_shared<DeclarationLocationsFinder>(
> - llvm::errs(), SourceLocationBeg, *Unit);
> + llvm::errs(), SourceLocationBeg, Unit->getASTContext(),
> + Unit->getPreprocessor());
> index::IndexingOptions IndexOpts;
> IndexOpts.SystemSymbolFilter =
> index::IndexingOptions::SystemSymbolFilterKind::All;
> IndexOpts.IndexFunctionLocals = true;
> - index::indexASTUnit(*Unit, DeclLocationsFinder, IndexOpts);
> +
> + indexTopLevelDecls(Unit->getASTContext(), Unit->getTopLevelDecls(),
> + DeclLocationsFinder, IndexOpts);
>
> return DeclLocationsFinder->takeLocations();
> }
>
> SourceLocation ClangdUnit::getBeginningOfIdentifier(const Position &Pos,
> - const FileEntry *FE) const {
> + const FileEntry *FE)
> const {
> +
> // The language server protocol uses zero-based line and column numbers.
> // Clang uses one-based numbers.
> - SourceLocation InputLocation = Unit->getLocation(FE, Pos.line + 1,
> - Pos.character + 1);
>
> + const ASTContext &AST = Unit->getASTContext();
> + const SourceManager &SourceMgr = AST.getSourceManager();
> +
> + SourceLocation InputLocation =
> + getMacroArgExpandedLocation(SourceMgr, FE, Pos);
> if (Pos.character == 0) {
> return InputLocation;
> }
> @@ -396,20 +680,97 @@ SourceLocation ClangdUnit::getBeginningO
> // token. If so, Take the beginning of this token.
> // (It should be the same identifier because you can't have two adjacent
> // identifiers without another token in between.)
> - SourceLocation PeekBeforeLocation = Unit->getLocation(FE, Pos.line + 1,
> - Pos.character);
> - const SourceManager &SourceMgr = Unit->getSourceManager();
> + SourceLocation PeekBeforeLocation = getMacroArgExpandedLocation(
> + SourceMgr, FE, Position{Pos.line, Pos.character - 1});
> Token Result;
> if (Lexer::getRawToken(PeekBeforeLocation, Result, SourceMgr,
> - Unit->getASTContext().getLangOpts(), false)) {
> + AST.getLangOpts(), false)) {
> // getRawToken failed, just use InputLocation.
> return InputLocation;
> }
>
> if (Result.is(tok::raw_identifier)) {
> return Lexer::GetBeginningOfToken(PeekBeforeLocation, SourceMgr,
> - Unit->getASTContext().getLangOpts());
> + Unit->getASTContext().getLangOpts());
> }
>
> return InputLocation;
> }
> +
> +void ClangdUnit::ParsedAST::ensurePreambleDeclsDeserialized() {
> + if (PendingTopLevelDecls.empty())
> + return;
> +
> + std::vector<const Decl *> Resolved;
> + Resolved.reserve(PendingTopLevelDecls.size());
> +
> + ExternalASTSource &Source = *getASTContext().getExternalSource();
> + for (serialization::DeclID TopLevelDecl : PendingTopLevelDecls) {
> + // Resolve the declaration ID to an actual declaration, possibly
> + // deserializing the declaration in the process.
> + if (Decl *D = Source.GetExternalDecl(TopLevelDecl))
> + Resolved.push_back(D);
> + }
> +
> + TopLevelDecls.reserve(TopLevelDecls.size() + PendingTopLevelDecls.size());
> + TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(),
> Resolved.end());
> +
> + PendingTopLevelDecls.clear();
> +}
> +
> +ClangdUnit::ParsedAST::ParsedAST(ParsedAST &&Other) = default;
> +
> +ClangdUnit::ParsedAST &ClangdUnit::ParsedAST::
> +operator=(ParsedAST &&Other) = default;
> +
> +ClangdUnit::ParsedAST::~ParsedAST() {
> + if (Action) {
> + Action->EndSourceFile();
> + }
> +}
> +
> +ASTContext &ClangdUnit::ParsedAST::getASTContext() {
> + return Clang->getASTContext();
> +}
> +
> +const ASTContext &ClangdUnit::ParsedAST::getASTContext() const {
> + return Clang->getASTContext();
> +}
> +
> +Preprocessor &ClangdUnit::ParsedAST::getPreprocessor() {
> + return Clang->getPreprocessor();
> +}
> +
> +const Preprocessor &ClangdUnit::ParsedAST::getPreprocessor() const {
> + return Clang->getPreprocessor();
> +}
> +
> +ArrayRef<const Decl *> ClangdUnit::ParsedAST::getTopLevelDecls() {
> + ensurePreambleDeclsDeserialized();
> + return TopLevelDecls;
> +}
> +
> +const std::vector<DiagWithFixIts> &
> +ClangdUnit::ParsedAST::getDiagnostics() const {
> + return Diags;
> +}
> +
> +ClangdUnit::ParsedAST::ParsedAST(
> + std::unique_ptr<CompilerInstance> Clang,
> + std::unique_ptr<FrontendAction> Action,
> + std::vector<const Decl *> TopLevelDecls,
> + std::vector<serialization::DeclID> PendingTopLevelDecls,
> + std::vector<DiagWithFixIts> Diags)
> + : Clang(std::move(Clang)), Action(std::move(Action)),
> + Diags(std::move(Diags)), TopLevelDecls(std::move(TopLevelDecls)),
> + PendingTopLevelDecls(std::move(PendingTopLevelDecls)) {
> + assert(this->Clang);
> + assert(this->Action);
> +}
> +
> +ClangdUnit::PreambleData::PreambleData(
> + PrecompiledPreamble Preamble,
> + std::vector<serialization::DeclID> TopLevelDeclIDs,
> + std::vector<DiagWithFixIts> Diags)
> + : Preamble(std::move(Preamble)),
> + TopLevelDeclIDs(std::move(TopLevelDeclIDs)), Diags(std::move(Diags)) {}
>
> Modified: clang-tools-extra/trunk/clangd/ClangdUnit.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-
> extra/trunk/clangd/ClangdUnit.h?rev=308738&r1=308737&r2=308738&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdUnit.h (original)
> +++ clang-tools-extra/trunk/clangd/ClangdUnit.h Fri Jul 21 06:29:29 2017
> @@ -13,6 +13,9 @@
> #include "Path.h"
> #include "Protocol.h"
> #include "clang/Frontend/ASTUnit.h"
> +#include "clang/Frontend/PrecompiledPreamble.h"
> +#include "clang/Serialization/ASTBitCodes.h"
> +#include "clang/Tooling/CompilationDatabase.h"
> #include "clang/Tooling/Core/Replacement.h"
> #include <memory>
>
> @@ -70,11 +73,82 @@ public:
> void dumpAST(llvm::raw_ostream &OS) const;
>
> private:
> + /// Stores and provides access to parsed AST.
> + class ParsedAST {
> + public:
> + /// Attempts to run Clang and store parsed AST. If \p Preamble is non-
> null
> + /// it is reused during parsing.
> + static llvm::Optional<ParsedAST>
> + Build(std::unique_ptr<clang::CompilerInvocation> CI,
> + const PrecompiledPreamble *Preamble,
> + ArrayRef<serialization::DeclID> PreambleDeclIDs,
> + std::unique_ptr<llvm::MemoryBuffer> Buffer,
> + std::shared_ptr<PCHContainerOperations> PCHs,
> + IntrusiveRefCntPtr<vfs::FileSystem> VFS);
> +
> + ParsedAST(ParsedAST &&Other);
> + ParsedAST &operator=(ParsedAST &&Other);
> +
> + ~ParsedAST();
> +
> + ASTContext &getASTContext();
> + const ASTContext &getASTContext() const;
> +
> + Preprocessor &getPreprocessor();
> + const Preprocessor &getPreprocessor() const;
> +
> + /// This function returns all top-level decls, including those that come
> + /// from Preamble. Decls, coming from Preamble, have to be deserialized,
> so
> + /// this call might be expensive.
> + ArrayRef<const Decl *> getTopLevelDecls();
> +
> + const std::vector<DiagWithFixIts> &getDiagnostics() const;
> +
> + private:
> + ParsedAST(std::unique_ptr<CompilerInstance> Clang,
> + std::unique_ptr<FrontendAction> Action,
> + std::vector<const Decl *> TopLevelDecls,
> + std::vector<serialization::DeclID> PendingTopLevelDecls,
> + std::vector<DiagWithFixIts> Diags);
> +
> + private:
> + void ensurePreambleDeclsDeserialized();
> +
> + // We store an "incomplete" FrontendAction (i.e. no EndSourceFile was
> called
> + // on it) and CompilerInstance used to run it. That way we don't have to
> do
> + // complex memory management of all Clang structures on our own. (They
> are
> + // stored in CompilerInstance and cleaned up by
> + // FrontendAction.EndSourceFile).
> + std::unique_ptr<CompilerInstance> Clang;
> + std::unique_ptr<FrontendAction> Action;
> +
> + // Data, stored after parsing.
> + std::vector<DiagWithFixIts> Diags;
> + std::vector<const Decl *> TopLevelDecls;
> + std::vector<serialization::DeclID> PendingTopLevelDecls;
> + };
> +
> + // Store Preamble and all associated data
> + struct PreambleData {
> + PreambleData(PrecompiledPreamble Preamble,
> + std::vector<serialization::DeclID> TopLevelDeclIDs,
> + std::vector<DiagWithFixIts> Diags);
> +
> + PrecompiledPreamble Preamble;
> + std::vector<serialization::DeclID> TopLevelDeclIDs;
> + std::vector<DiagWithFixIts> Diags;
> + };
> +
> + SourceLocation getBeginningOfIdentifier(const Position &Pos,
> + const FileEntry *FE) const;
> +
> Path FileName;
> - std::unique_ptr<ASTUnit> Unit;
> - std::shared_ptr<PCHContainerOperations> PCHs;
> + tooling::CompileCommand Command;
>
> - SourceLocation getBeginningOfIdentifier(const Position& Pos, const
> FileEntry* FE) const;
> + llvm::Optional<PreambleData> Preamble;
> + llvm::Optional<ParsedAST> Unit;
> +
> + std::shared_ptr<PCHContainerOperations> PCHs;
> };
>
> } // namespace clangd
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list