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-boun...@lists.llvm.org] On Behalf Of > Ilya Biryukov via cfe-commits > Sent: Friday, July 21, 2017 6:29 > To: cfe-commits@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@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits