2020-04-02 16:53:23 +08:00
|
|
|
//===--- PreambleTests.cpp --------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Annotations.h"
|
|
|
|
#include "Compiler.h"
|
2020-04-02 16:53:45 +08:00
|
|
|
#include "Headers.h"
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
#include "Hover.h"
|
2020-04-02 16:53:23 +08:00
|
|
|
#include "Preamble.h"
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
#include "SourceCode.h"
|
2020-04-02 16:53:23 +08:00
|
|
|
#include "TestFS.h"
|
2020-04-23 23:44:51 +08:00
|
|
|
#include "TestTU.h"
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
#include "XRefs.h"
|
|
|
|
#include "clang/Format/Format.h"
|
2020-04-23 23:44:51 +08:00
|
|
|
#include "clang/Frontend/PrecompiledPreamble.h"
|
2020-04-02 16:53:23 +08:00
|
|
|
#include "clang/Lex/PreprocessorOptions.h"
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2020-04-23 23:44:51 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2020-04-02 16:53:23 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
#include "llvm/Support/Error.h"
|
2020-04-23 23:44:51 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/VirtualFileSystem.h"
|
2020-04-02 16:53:23 +08:00
|
|
|
#include "gmock/gmock.h"
|
|
|
|
#include "gtest/gtest.h"
|
2020-04-23 23:44:51 +08:00
|
|
|
#include <clang/Frontend/FrontendActions.h>
|
2020-04-02 16:53:45 +08:00
|
|
|
#include <memory>
|
2020-04-02 16:53:23 +08:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2020-05-14 18:20:33 +08:00
|
|
|
using testing::Contains;
|
2020-04-23 23:44:51 +08:00
|
|
|
using testing::Field;
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
using testing::Matcher;
|
2020-05-14 18:20:33 +08:00
|
|
|
using testing::MatchesRegex;
|
2020-04-23 23:44:51 +08:00
|
|
|
|
2020-04-02 16:53:23 +08:00
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
|
|
|
|
2020-04-02 16:53:45 +08:00
|
|
|
MATCHER_P2(Distance, File, D, "") {
|
|
|
|
return arg.first() == File && arg.second == D;
|
|
|
|
}
|
|
|
|
|
2020-04-23 23:44:51 +08:00
|
|
|
// Builds a preamble for BaselineContents, patches it for ModifiedContents and
|
|
|
|
// returns the includes in the patch.
|
|
|
|
IncludeStructure
|
|
|
|
collectPatchedIncludes(llvm::StringRef ModifiedContents,
|
|
|
|
llvm::StringRef BaselineContents,
|
|
|
|
llvm::StringRef MainFileName = "main.cpp") {
|
2020-06-17 17:53:32 +08:00
|
|
|
MockFS FS;
|
2020-05-14 18:23:21 +08:00
|
|
|
auto TU = TestTU::withCode(BaselineContents);
|
2020-04-02 16:53:45 +08:00
|
|
|
TU.Filename = MainFileName.str();
|
2020-04-23 23:44:51 +08:00
|
|
|
// ms-compatibility changes meaning of #import, make sure it is turned off.
|
2020-04-02 16:53:45 +08:00
|
|
|
TU.ExtraArgs = {"-fno-ms-compatibility"};
|
2020-05-14 18:23:21 +08:00
|
|
|
auto BaselinePreamble = TU.preamble();
|
|
|
|
// Create the patch.
|
2020-05-29 18:35:16 +08:00
|
|
|
TU.Code = ModifiedContents.str();
|
2020-06-05 00:26:52 +08:00
|
|
|
auto PI = TU.inputs(FS);
|
2020-04-02 16:53:45 +08:00
|
|
|
auto PP = PreamblePatch::create(testPath(TU.Filename), PI, *BaselinePreamble);
|
|
|
|
// Collect patch contents.
|
2020-04-02 16:53:23 +08:00
|
|
|
IgnoreDiagnostics Diags;
|
2020-04-23 23:44:51 +08:00
|
|
|
auto CI = buildCompilerInvocation(PI, Diags);
|
|
|
|
PP.apply(*CI);
|
2020-04-02 16:53:45 +08:00
|
|
|
// Run preprocessor over the modified contents with patched Invocation. We
|
|
|
|
// provide a preamble and trim contents to ensure only the implicit header
|
|
|
|
// introduced by the patch is parsed and nothing else.
|
|
|
|
// We don't run PP directly over the patch cotents to test production
|
|
|
|
// behaviour.
|
2020-04-23 23:44:51 +08:00
|
|
|
auto Bounds = Lexer::ComputePreamble(ModifiedContents, *CI->getLangOpts());
|
2020-06-18 00:09:54 +08:00
|
|
|
auto Clang =
|
|
|
|
prepareCompilerInstance(std::move(CI), &BaselinePreamble->Preamble,
|
|
|
|
llvm::MemoryBuffer::getMemBufferCopy(
|
|
|
|
ModifiedContents.slice(0, Bounds.Size).str()),
|
|
|
|
PI.TFS->view(PI.CompileCommand.Directory), Diags);
|
2020-04-23 23:44:51 +08:00
|
|
|
PreprocessOnlyAction Action;
|
|
|
|
if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
|
|
|
|
ADD_FAILURE() << "failed begin source file";
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
IncludeStructure Includes;
|
|
|
|
Clang->getPreprocessor().addPPCallbacks(
|
|
|
|
collectIncludeStructureCallback(Clang->getSourceManager(), &Includes));
|
|
|
|
if (llvm::Error Err = Action.Execute()) {
|
|
|
|
ADD_FAILURE() << "failed to execute action: " << std::move(Err);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
Action.EndSourceFile();
|
|
|
|
return Includes;
|
|
|
|
}
|
2020-04-02 16:53:23 +08:00
|
|
|
|
2020-04-23 23:44:51 +08:00
|
|
|
// Check preamble lexing logic by building an empty preamble and patching it
|
|
|
|
// with all the contents.
|
|
|
|
TEST(PreamblePatchTest, IncludeParsing) {
|
2020-04-02 16:53:23 +08:00
|
|
|
// We expect any line with a point to show up in the patch.
|
|
|
|
llvm::StringRef Cases[] = {
|
|
|
|
// Only preamble
|
|
|
|
R"cpp(^#include "a.h")cpp",
|
|
|
|
// Both preamble and mainfile
|
|
|
|
R"cpp(
|
|
|
|
^#include "a.h"
|
|
|
|
garbage, finishes preamble
|
|
|
|
#include "a.h")cpp",
|
|
|
|
// Mixed directives
|
|
|
|
R"cpp(
|
|
|
|
^#include "a.h"
|
|
|
|
#pragma directive
|
|
|
|
// some comments
|
|
|
|
^#include_next <a.h>
|
|
|
|
#ifdef skipped
|
|
|
|
^#import "a.h"
|
|
|
|
#endif)cpp",
|
|
|
|
// Broken directives
|
|
|
|
R"cpp(
|
|
|
|
#include "a
|
|
|
|
^#include "a.h"
|
|
|
|
#include <b
|
|
|
|
^#include <b.h>)cpp",
|
2020-05-05 23:55:11 +08:00
|
|
|
// Directive is not part of preamble if it is not the token immediately
|
|
|
|
// followed by the hash (#).
|
|
|
|
R"cpp(
|
|
|
|
^#include "a.h"
|
|
|
|
#/**/include <b.h>)cpp",
|
2020-04-02 16:53:23 +08:00
|
|
|
};
|
|
|
|
|
2020-07-05 08:41:27 +08:00
|
|
|
for (const auto &Case : Cases) {
|
2020-04-02 16:53:23 +08:00
|
|
|
Annotations Test(Case);
|
|
|
|
const auto Code = Test.code();
|
|
|
|
SCOPED_TRACE(Code);
|
|
|
|
|
2020-04-23 23:44:51 +08:00
|
|
|
auto Includes =
|
|
|
|
collectPatchedIncludes(Code, /*BaselineContents=*/"").MainFileIncludes;
|
|
|
|
auto Points = Test.points();
|
|
|
|
ASSERT_EQ(Includes.size(), Points.size());
|
|
|
|
for (size_t I = 0, E = Includes.size(); I != E; ++I)
|
|
|
|
EXPECT_EQ(Includes[I].HashLine, Points[I].line);
|
2020-04-02 16:53:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PreamblePatchTest, ContainsNewIncludes) {
|
2020-04-23 23:44:51 +08:00
|
|
|
constexpr llvm::StringLiteral BaselineContents = R"cpp(
|
|
|
|
#include <a.h>
|
|
|
|
#include <b.h> // This will be removed
|
|
|
|
#include <c.h>
|
|
|
|
)cpp";
|
|
|
|
constexpr llvm::StringLiteral ModifiedContents = R"cpp(
|
|
|
|
#include <a.h>
|
|
|
|
#include <c.h> // This has changed a line.
|
|
|
|
#include <c.h> // This is a duplicate.
|
|
|
|
#include <d.h> // This is newly introduced.
|
|
|
|
)cpp";
|
|
|
|
auto Includes = collectPatchedIncludes(ModifiedContents, BaselineContents)
|
|
|
|
.MainFileIncludes;
|
|
|
|
EXPECT_THAT(Includes, ElementsAre(AllOf(Field(&Inclusion::Written, "<d.h>"),
|
|
|
|
Field(&Inclusion::HashLine, 4))));
|
2020-04-02 16:53:23 +08:00
|
|
|
}
|
|
|
|
|
2020-04-23 23:44:51 +08:00
|
|
|
TEST(PreamblePatchTest, MainFileIsEscaped) {
|
|
|
|
auto Includes = collectPatchedIncludes("#include <a.h>", "", "file\"name.cpp")
|
|
|
|
.MainFileIncludes;
|
|
|
|
EXPECT_THAT(Includes, ElementsAre(AllOf(Field(&Inclusion::Written, "<a.h>"),
|
|
|
|
Field(&Inclusion::HashLine, 0))));
|
|
|
|
}
|
2020-04-02 16:53:45 +08:00
|
|
|
|
|
|
|
TEST(PreamblePatchTest, PatchesPreambleIncludes) {
|
2020-06-17 17:53:32 +08:00
|
|
|
MockFS FS;
|
2020-04-02 16:53:45 +08:00
|
|
|
IgnoreDiagnostics Diags;
|
|
|
|
auto TU = TestTU::withCode(R"cpp(
|
|
|
|
#include "a.h"
|
|
|
|
#include "c.h"
|
|
|
|
)cpp");
|
|
|
|
TU.AdditionalFiles["a.h"] = "#include \"b.h\"";
|
|
|
|
TU.AdditionalFiles["b.h"] = "";
|
|
|
|
TU.AdditionalFiles["c.h"] = "";
|
2020-06-05 00:26:52 +08:00
|
|
|
auto PI = TU.inputs(FS);
|
2020-04-02 16:53:45 +08:00
|
|
|
auto BaselinePreamble = buildPreamble(
|
|
|
|
TU.Filename, *buildCompilerInvocation(PI, Diags), PI, true, nullptr);
|
|
|
|
// We drop c.h from modified and add a new header. Since the latter is patched
|
|
|
|
// we should only get a.h in preamble includes.
|
|
|
|
TU.Code = R"cpp(
|
|
|
|
#include "a.h"
|
|
|
|
#include "b.h"
|
|
|
|
)cpp";
|
2020-06-05 00:26:52 +08:00
|
|
|
auto PP = PreamblePatch::create(testPath(TU.Filename), TU.inputs(FS),
|
2020-04-02 16:53:45 +08:00
|
|
|
*BaselinePreamble);
|
|
|
|
// Only a.h should exists in the preamble, as c.h has been dropped and b.h was
|
|
|
|
// newly introduced.
|
|
|
|
EXPECT_THAT(PP.preambleIncludes(),
|
|
|
|
ElementsAre(AllOf(Field(&Inclusion::Written, "\"a.h\""),
|
|
|
|
Field(&Inclusion::Resolved, testPath("a.h")))));
|
|
|
|
}
|
2020-05-14 18:20:33 +08:00
|
|
|
|
|
|
|
llvm::Optional<ParsedAST> createPatchedAST(llvm::StringRef Baseline,
|
|
|
|
llvm::StringRef Modified) {
|
|
|
|
auto BaselinePreamble = TestTU::withCode(Baseline).preamble();
|
|
|
|
if (!BaselinePreamble) {
|
|
|
|
ADD_FAILURE() << "Failed to build baseline preamble";
|
|
|
|
return llvm::None;
|
|
|
|
}
|
|
|
|
|
|
|
|
IgnoreDiagnostics Diags;
|
2020-06-17 17:53:32 +08:00
|
|
|
MockFS FS;
|
2020-05-14 18:20:33 +08:00
|
|
|
auto TU = TestTU::withCode(Modified);
|
2020-06-05 00:26:52 +08:00
|
|
|
auto CI = buildCompilerInvocation(TU.inputs(FS), Diags);
|
2020-05-14 18:20:33 +08:00
|
|
|
if (!CI) {
|
|
|
|
ADD_FAILURE() << "Failed to build compiler invocation";
|
|
|
|
return llvm::None;
|
|
|
|
}
|
2020-06-05 00:26:52 +08:00
|
|
|
return ParsedAST::build(testPath(TU.Filename), TU.inputs(FS), std::move(CI),
|
|
|
|
{}, BaselinePreamble);
|
2020-05-14 18:20:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string getPreamblePatch(llvm::StringRef Baseline,
|
|
|
|
llvm::StringRef Modified) {
|
|
|
|
auto BaselinePreamble = TestTU::withCode(Baseline).preamble();
|
|
|
|
if (!BaselinePreamble) {
|
|
|
|
ADD_FAILURE() << "Failed to build baseline preamble";
|
|
|
|
return "";
|
|
|
|
}
|
2020-06-17 17:53:32 +08:00
|
|
|
MockFS FS;
|
2020-05-14 18:20:33 +08:00
|
|
|
auto TU = TestTU::withCode(Modified);
|
2020-06-05 00:26:52 +08:00
|
|
|
return PreamblePatch::create(testPath("main.cpp"), TU.inputs(FS),
|
2020-05-14 18:20:33 +08:00
|
|
|
*BaselinePreamble)
|
|
|
|
.text()
|
|
|
|
.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PreamblePatchTest, Define) {
|
|
|
|
// BAR should be defined while parsing the AST.
|
|
|
|
struct {
|
2020-07-13 15:04:29 +08:00
|
|
|
const char *const Contents;
|
|
|
|
const char *const ExpectedPatch;
|
2020-05-14 18:20:33 +08:00
|
|
|
} Cases[] = {
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
#define BAR
|
|
|
|
[[BAR]])cpp",
|
|
|
|
R"cpp(#line 0 ".*main.cpp"
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
#line 2
|
|
|
|
#define BAR
|
2020-05-14 18:20:33 +08:00
|
|
|
)cpp",
|
|
|
|
},
|
|
|
|
// multiline macro
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
#define BAR \
|
|
|
|
|
|
|
|
[[BAR]])cpp",
|
|
|
|
R"cpp(#line 0 ".*main.cpp"
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
#line 2
|
|
|
|
#define BAR
|
2020-05-14 18:20:33 +08:00
|
|
|
)cpp",
|
|
|
|
},
|
|
|
|
// multiline macro
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
#define \
|
|
|
|
BAR
|
|
|
|
[[BAR]])cpp",
|
|
|
|
R"cpp(#line 0 ".*main.cpp"
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
#line 3
|
|
|
|
#define BAR
|
2020-05-14 18:20:33 +08:00
|
|
|
)cpp",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const auto &Case : Cases) {
|
|
|
|
SCOPED_TRACE(Case.Contents);
|
|
|
|
Annotations Modified(Case.Contents);
|
|
|
|
EXPECT_THAT(getPreamblePatch("", Modified.code()),
|
2020-07-13 15:04:29 +08:00
|
|
|
MatchesRegex(Case.ExpectedPatch));
|
2020-05-14 18:20:33 +08:00
|
|
|
|
|
|
|
auto AST = createPatchedAST("", Modified.code());
|
|
|
|
ASSERT_TRUE(AST);
|
2021-03-15 17:18:12 +08:00
|
|
|
std::vector<Range> MacroRefRanges;
|
|
|
|
for (auto &M : AST->getMacros().MacroRefs) {
|
|
|
|
for (auto &O : M.getSecond())
|
|
|
|
MacroRefRanges.push_back(O.Rng);
|
|
|
|
}
|
|
|
|
EXPECT_THAT(MacroRefRanges, Contains(Modified.range()));
|
2020-05-14 18:20:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PreamblePatchTest, OrderingPreserved) {
|
|
|
|
llvm::StringLiteral Baseline = "#define BAR(X) X";
|
|
|
|
Annotations Modified(R"cpp(
|
|
|
|
#define BAR(X, Y) X Y
|
|
|
|
#define BAR(X) X
|
|
|
|
[[BAR]](int y);
|
|
|
|
)cpp");
|
|
|
|
|
|
|
|
llvm::StringLiteral ExpectedPatch(R"cpp(#line 0 ".*main.cpp"
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
#line 2
|
|
|
|
#define BAR\(X, Y\) X Y
|
|
|
|
#line 3
|
|
|
|
#define BAR\(X\) X
|
2020-05-14 18:20:33 +08:00
|
|
|
)cpp");
|
|
|
|
EXPECT_THAT(getPreamblePatch(Baseline, Modified.code()),
|
|
|
|
MatchesRegex(ExpectedPatch.str()));
|
|
|
|
|
|
|
|
auto AST = createPatchedAST(Baseline, Modified.code());
|
|
|
|
ASSERT_TRUE(AST);
|
|
|
|
}
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
|
|
|
|
TEST(PreamblePatchTest, LocateMacroAtWorks) {
|
|
|
|
struct {
|
2020-07-13 15:04:29 +08:00
|
|
|
const char *const Baseline;
|
|
|
|
const char *const Modified;
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
} Cases[] = {
|
|
|
|
// Addition of new directive
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
R"cpp(
|
|
|
|
#define $def^FOO
|
|
|
|
$use^FOO)cpp",
|
|
|
|
},
|
|
|
|
// Available inside preamble section
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
R"cpp(
|
|
|
|
#define $def^FOO
|
|
|
|
#undef $use^FOO)cpp",
|
|
|
|
},
|
|
|
|
// Available after undef, as we don't patch those
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
R"cpp(
|
|
|
|
#define $def^FOO
|
|
|
|
#undef FOO
|
|
|
|
$use^FOO)cpp",
|
|
|
|
},
|
|
|
|
// Identifier on a different line
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
R"cpp(
|
|
|
|
#define \
|
|
|
|
$def^FOO
|
|
|
|
$use^FOO)cpp",
|
|
|
|
},
|
|
|
|
// In presence of comment tokens
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
R"cpp(
|
|
|
|
#\
|
|
|
|
define /* FOO */\
|
|
|
|
/* FOO */ $def^FOO
|
|
|
|
$use^FOO)cpp",
|
|
|
|
},
|
|
|
|
// Moved around
|
|
|
|
{
|
|
|
|
"#define FOO",
|
|
|
|
R"cpp(
|
|
|
|
#define BAR
|
|
|
|
#define $def^FOO
|
|
|
|
$use^FOO)cpp",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
for (const auto &Case : Cases) {
|
|
|
|
SCOPED_TRACE(Case.Modified);
|
|
|
|
llvm::Annotations Modified(Case.Modified);
|
|
|
|
auto AST = createPatchedAST(Case.Baseline, Modified.code());
|
|
|
|
ASSERT_TRUE(AST);
|
|
|
|
|
|
|
|
const auto &SM = AST->getSourceManager();
|
|
|
|
auto *MacroTok = AST->getTokens().spelledTokenAt(
|
|
|
|
SM.getComposedLoc(SM.getMainFileID(), Modified.point("use")));
|
|
|
|
ASSERT_TRUE(MacroTok);
|
|
|
|
|
|
|
|
auto FoundMacro = locateMacroAt(*MacroTok, AST->getPreprocessor());
|
|
|
|
ASSERT_TRUE(FoundMacro);
|
|
|
|
EXPECT_THAT(FoundMacro->Name, "FOO");
|
|
|
|
|
|
|
|
auto MacroLoc = FoundMacro->NameLoc;
|
|
|
|
EXPECT_EQ(SM.getFileID(MacroLoc), SM.getMainFileID());
|
|
|
|
EXPECT_EQ(SM.getFileOffset(MacroLoc), Modified.point("def"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PreamblePatchTest, LocateMacroAtDeletion) {
|
|
|
|
{
|
|
|
|
// We don't patch deleted define directives, make sure we don't crash.
|
|
|
|
llvm::StringLiteral Baseline = "#define FOO";
|
|
|
|
llvm::Annotations Modified("^FOO");
|
|
|
|
|
|
|
|
auto AST = createPatchedAST(Baseline, Modified.code());
|
|
|
|
ASSERT_TRUE(AST);
|
|
|
|
|
|
|
|
const auto &SM = AST->getSourceManager();
|
|
|
|
auto *MacroTok = AST->getTokens().spelledTokenAt(
|
|
|
|
SM.getComposedLoc(SM.getMainFileID(), Modified.point()));
|
|
|
|
ASSERT_TRUE(MacroTok);
|
|
|
|
|
|
|
|
auto FoundMacro = locateMacroAt(*MacroTok, AST->getPreprocessor());
|
|
|
|
ASSERT_TRUE(FoundMacro);
|
|
|
|
EXPECT_THAT(FoundMacro->Name, "FOO");
|
|
|
|
auto HI =
|
|
|
|
getHover(*AST, offsetToPosition(Modified.code(), Modified.point()),
|
|
|
|
format::getLLVMStyle(), nullptr);
|
|
|
|
ASSERT_TRUE(HI);
|
|
|
|
EXPECT_THAT(HI->Definition, testing::IsEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Offset is valid, but underlying text is different.
|
|
|
|
llvm::StringLiteral Baseline = "#define FOO";
|
|
|
|
Annotations Modified(R"cpp(#define BAR
|
|
|
|
^FOO")cpp");
|
|
|
|
|
|
|
|
auto AST = createPatchedAST(Baseline, Modified.code());
|
|
|
|
ASSERT_TRUE(AST);
|
|
|
|
|
|
|
|
auto HI = getHover(*AST, Modified.point(), format::getLLVMStyle(), nullptr);
|
|
|
|
ASSERT_TRUE(HI);
|
|
|
|
EXPECT_THAT(HI->Definition, "#define BAR");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-27 00:16:57 +08:00
|
|
|
MATCHER_P(referenceRangeIs, R, "") { return arg.Loc.range == R; }
|
|
|
|
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
TEST(PreamblePatchTest, RefsToMacros) {
|
|
|
|
struct {
|
2020-07-13 15:04:29 +08:00
|
|
|
const char *const Baseline;
|
|
|
|
const char *const Modified;
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
} Cases[] = {
|
|
|
|
// Newly added
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
R"cpp(
|
|
|
|
#define ^FOO
|
|
|
|
^[[FOO]])cpp",
|
|
|
|
},
|
|
|
|
// Moved around
|
|
|
|
{
|
|
|
|
"#define FOO",
|
|
|
|
R"cpp(
|
|
|
|
#define BAR
|
|
|
|
#define ^FOO
|
|
|
|
^[[FOO]])cpp",
|
|
|
|
},
|
|
|
|
// Ref in preamble section
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
R"cpp(
|
|
|
|
#define ^FOO
|
|
|
|
#undef ^FOO)cpp",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const auto &Case : Cases) {
|
|
|
|
Annotations Modified(Case.Modified);
|
|
|
|
auto AST = createPatchedAST("", Modified.code());
|
|
|
|
ASSERT_TRUE(AST);
|
|
|
|
|
|
|
|
const auto &SM = AST->getSourceManager();
|
2021-01-27 00:16:57 +08:00
|
|
|
std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations;
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
for (const auto &R : Modified.ranges())
|
2021-01-27 00:16:57 +08:00
|
|
|
ExpectedLocations.push_back(referenceRangeIs(R));
|
[clangd] locateMacroAt handles patched macros
Summary: Depends on D79992.
This patch changes locateMacroAt to perform #line directive substitution
for macro identifier locations.
We first check whether a location is inside a file included through
built-in header. If so we check whether line directive maps it back to
the main file, and afterwards use TokenBuffers to find exact location of
the identifier on the line.
Instead of performing the mapping in locateMacroAt, we could also store
a mapping inside the ParsedAST whenever we use a patched preamble. But
that would imply adding more responsibility to ParsedAST and paying for
the mapping even when it is not going to be used.
====
Go-To-Definition:
Later on these locations are used for serving go-to-definition requests,
this enables jumping to definition inside the preamble section in
presence of patched macros.
=====
Go-To-Refs:
Macro references in main file are collected separetely and stored as a
map from macro's symbol id to reference ranges. Those ranges are
computed inside PPCallbacks, hence we don't have access to TokenBuffer.
In presence of preamble patch, any reference to a macro inside the
preamble section will unfortunately have the wrong range. They'll point
into the patch rather than the main file. Hence during findReferences,
we won't get any ranges reported for those.
Fixing those requires:
- Lexing the preamble section to figure out "real range" of a patched
macro definition
- Postponing range/location calculations until a later step in which we
have access to tokenbuffers.
This patch trades some accuracy in favor of code complexity. We don't do
any patching for references inside the preamble patch but get any
reference inside the main file for free.
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D80198
2020-05-14 18:26:47 +08:00
|
|
|
|
|
|
|
for (const auto &P : Modified.points()) {
|
|
|
|
auto *MacroTok = AST->getTokens().spelledTokenAt(SM.getComposedLoc(
|
|
|
|
SM.getMainFileID(),
|
|
|
|
llvm::cantFail(positionToOffset(Modified.code(), P))));
|
|
|
|
ASSERT_TRUE(MacroTok);
|
|
|
|
EXPECT_THAT(findReferences(*AST, P, 0).References,
|
|
|
|
testing::ElementsAreArray(ExpectedLocations));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(TranslatePreamblePatchLocation, Simple) {
|
|
|
|
auto TU = TestTU::withHeaderCode(R"cpp(
|
|
|
|
#line 3 "main.cpp"
|
|
|
|
int foo();)cpp");
|
|
|
|
// Presumed line/col needs to be valid in the main file.
|
|
|
|
TU.Code = R"cpp(// line 1
|
|
|
|
// line 2
|
|
|
|
// line 3
|
|
|
|
// line 4)cpp";
|
|
|
|
TU.Filename = "main.cpp";
|
|
|
|
TU.HeaderFilename = "__preamble_patch__.h";
|
|
|
|
TU.ImplicitHeaderGuard = false;
|
|
|
|
|
|
|
|
auto AST = TU.build();
|
|
|
|
auto &SM = AST.getSourceManager();
|
|
|
|
auto &ND = findDecl(AST, "foo");
|
|
|
|
EXPECT_NE(SM.getFileID(ND.getLocation()), SM.getMainFileID());
|
|
|
|
|
|
|
|
auto TranslatedLoc = translatePreamblePatchLocation(ND.getLocation(), SM);
|
|
|
|
auto DecompLoc = SM.getDecomposedLoc(TranslatedLoc);
|
|
|
|
EXPECT_EQ(DecompLoc.first, SM.getMainFileID());
|
|
|
|
EXPECT_EQ(SM.getLineNumber(DecompLoc.first, DecompLoc.second), 3U);
|
|
|
|
}
|
2020-06-17 03:21:45 +08:00
|
|
|
|
|
|
|
TEST(PreamblePatch, ModifiedBounds) {
|
|
|
|
struct {
|
2020-07-13 15:04:29 +08:00
|
|
|
const char *const Baseline;
|
|
|
|
const char *const Modified;
|
2020-06-17 03:21:45 +08:00
|
|
|
} Cases[] = {
|
|
|
|
// Size increased
|
|
|
|
{
|
|
|
|
"",
|
|
|
|
R"cpp(
|
|
|
|
#define FOO
|
|
|
|
FOO)cpp",
|
|
|
|
},
|
|
|
|
// Stayed same
|
|
|
|
{"#define FOO", "#define BAR"},
|
|
|
|
// Got smaller
|
|
|
|
{
|
|
|
|
R"cpp(
|
|
|
|
#define FOO
|
|
|
|
#undef FOO)cpp",
|
|
|
|
"#define FOO"},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const auto &Case : Cases) {
|
|
|
|
auto TU = TestTU::withCode(Case.Baseline);
|
|
|
|
auto BaselinePreamble = TU.preamble();
|
|
|
|
ASSERT_TRUE(BaselinePreamble);
|
|
|
|
|
|
|
|
Annotations Modified(Case.Modified);
|
|
|
|
TU.Code = Modified.code().str();
|
2020-06-18 00:09:54 +08:00
|
|
|
MockFS FS;
|
|
|
|
auto PP = PreamblePatch::create(testPath(TU.Filename), TU.inputs(FS),
|
|
|
|
*BaselinePreamble);
|
2020-06-17 03:21:45 +08:00
|
|
|
|
|
|
|
IgnoreDiagnostics Diags;
|
2020-06-18 00:09:54 +08:00
|
|
|
auto CI = buildCompilerInvocation(TU.inputs(FS), Diags);
|
2020-06-17 03:21:45 +08:00
|
|
|
ASSERT_TRUE(CI);
|
|
|
|
|
|
|
|
const auto ExpectedBounds =
|
|
|
|
Lexer::ComputePreamble(Case.Modified, *CI->getLangOpts());
|
|
|
|
EXPECT_EQ(PP.modifiedBounds().Size, ExpectedBounds.Size);
|
|
|
|
EXPECT_EQ(PP.modifiedBounds().PreambleEndsAtStartOfLine,
|
|
|
|
ExpectedBounds.PreambleEndsAtStartOfLine);
|
|
|
|
}
|
|
|
|
}
|
2021-03-15 17:18:12 +08:00
|
|
|
|
|
|
|
TEST(PreamblePatch, DropsDiagnostics) {
|
|
|
|
llvm::StringLiteral Code = "#define FOO\nx;/* error-ok */";
|
|
|
|
// First check that this code generates diagnostics.
|
|
|
|
EXPECT_THAT(*TestTU::withCode(Code).build().getDiagnostics(),
|
|
|
|
testing::Not(testing::IsEmpty()));
|
|
|
|
// Ensure they are dropeed when a patched preamble is used.
|
|
|
|
EXPECT_FALSE(createPatchedAST("", Code)->getDiagnostics());
|
|
|
|
}
|
2020-04-02 16:53:23 +08:00
|
|
|
} // namespace
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|