mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-01 12:43:47 +00:00
Implement semantic selections.
Summary: For a given cursor position, it returns ranges that are interesting to the user. Currently the semantic ranges correspond to the nodes of the syntax trees. Subscribers: mgorny, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D67358 llvm-svn: 371976
This commit is contained in:
parent
1aaefbca24
commit
73c09eb734
@ -66,6 +66,7 @@ add_clang_library(clangDaemon
|
||||
RIFF.cpp
|
||||
Selection.cpp
|
||||
SemanticHighlighting.cpp
|
||||
SemanticSelection.cpp
|
||||
SourceCode.cpp
|
||||
QueryDriverDatabase.cpp
|
||||
Threading.cpp
|
||||
|
64
clang-tools-extra/clangd/SemanticSelection.cpp
Normal file
64
clang-tools-extra/clangd/SemanticSelection.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
//===--- SemanticSelection.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 "SemanticSelection.h"
|
||||
#include "ParsedAST.h"
|
||||
#include "Protocol.h"
|
||||
#include "Selection.h"
|
||||
#include "SourceCode.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace clang {
|
||||
namespace clangd {
|
||||
namespace {
|
||||
// Adds Range \p R to the Result if it is distinct from the last added Range.
|
||||
// Assumes that only consecutive ranges can coincide.
|
||||
void addIfDistinct(const Range &R, std::vector<Range> &Result) {
|
||||
if (Result.empty() || Result.back() != R) {
|
||||
Result.push_back(R);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
llvm::Expected<std::vector<Range>> getSemanticRanges(ParsedAST &AST,
|
||||
Position Pos) {
|
||||
std::vector<Range> Result;
|
||||
const auto &SM = AST.getSourceManager();
|
||||
const auto &LangOpts = AST.getASTContext().getLangOpts();
|
||||
|
||||
auto FID = SM.getMainFileID();
|
||||
auto Offset = positionToOffset(SM.getBufferData(FID), Pos);
|
||||
if (!Offset) {
|
||||
return Offset.takeError();
|
||||
}
|
||||
|
||||
// Get node under the cursor.
|
||||
SelectionTree ST(AST.getASTContext(), AST.getTokens(), *Offset);
|
||||
for (const auto *Node = ST.commonAncestor(); Node != nullptr;
|
||||
Node = Node->Parent) {
|
||||
if (const Decl *D = Node->ASTNode.get<Decl>()) {
|
||||
if (llvm::isa<TranslationUnitDecl>(D)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto SR = toHalfOpenFileRange(SM, LangOpts, Node->ASTNode.getSourceRange());
|
||||
if (!SR.hasValue() || SM.getFileID(SR->getBegin()) != SM.getMainFileID()) {
|
||||
continue;
|
||||
}
|
||||
Range R;
|
||||
R.start = sourceLocToPosition(SM, SR->getBegin());
|
||||
R.end = sourceLocToPosition(SM, SR->getEnd());
|
||||
addIfDistinct(R, Result);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
32
clang-tools-extra/clangd/SemanticSelection.h
Normal file
32
clang-tools-extra/clangd/SemanticSelection.h
Normal file
@ -0,0 +1,32 @@
|
||||
//===--- SemanticSelection.h -------------------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Features for giving interesting semantic ranges around the cursor.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICSELECTION_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICSELECTION_H
|
||||
#include "ParsedAST.h"
|
||||
#include "Protocol.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <vector>
|
||||
namespace clang {
|
||||
namespace clangd {
|
||||
|
||||
/// Returns the list of all interesting ranges around the Position \p Pos.
|
||||
/// The interesting ranges corresponds to the AST nodes in the SelectionTree
|
||||
/// containing \p Pos.
|
||||
/// Any range in the result strictly contains all the previous ranges in the
|
||||
/// result. front() is the inner most range. back() is the outermost range.
|
||||
llvm::Expected<std::vector<Range>> getSemanticRanges(ParsedAST &AST,
|
||||
Position Pos);
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICSELECTION_H
|
@ -56,6 +56,7 @@ add_unittest(ClangdUnitTests ClangdTests
|
||||
RIFFTests.cpp
|
||||
SelectionTests.cpp
|
||||
SemanticHighlightingTests.cpp
|
||||
SemanticSelectionTests.cpp
|
||||
SerializationTests.cpp
|
||||
SourceCodeTests.cpp
|
||||
SymbolCollectorTests.cpp
|
||||
|
143
clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
Normal file
143
clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
//===-- SemanticSelectionTests.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 "Matchers.h"
|
||||
#include "Protocol.h"
|
||||
#include "SemanticSelection.h"
|
||||
#include "SourceCode.h"
|
||||
#include "TestTU.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <vector>
|
||||
namespace clang {
|
||||
namespace clangd {
|
||||
namespace {
|
||||
using ::testing::ElementsAreArray;
|
||||
|
||||
TEST(SemanticSelection, All) {
|
||||
const char *Tests[] = {
|
||||
R"cpp( // Single statement in a function body.
|
||||
[[void func() [[{
|
||||
[[[[int v = [[1^00]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp( // Expression
|
||||
[[void func() [[{
|
||||
int a = 1;
|
||||
// int v = (10 + 2) * (a + a);
|
||||
[[[[int v = [[[[([[[[10^]] + 2]])]] * (a + a)]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp( // Function call.
|
||||
int add(int x, int y) { return x + y; }
|
||||
[[void callee() [[{
|
||||
// int res = add(11, 22);
|
||||
[[[[int res = [[add([[1^1]], 22)]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp( // Tricky macros.
|
||||
#define MUL ) * (
|
||||
[[void func() [[{
|
||||
// int var = (4 + 15 MUL 6 + 10);
|
||||
[[[[int var = [[[[([[4 + [[1^5]]]] MUL]] 6 + 10)]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp( // Cursor inside a macro.
|
||||
#define HASH(x) ((x) % 10)
|
||||
[[void func() [[{
|
||||
[[[[int a = [[HASH([[[[2^3]] + 34]])]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp( // Cursor on a macro.
|
||||
#define HASH(x) ((x) % 10)
|
||||
[[void func() [[{
|
||||
[[[[int a = [[HA^SH(23)]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp( // Multiple declaration.
|
||||
[[void func() [[{
|
||||
[[[[int var1, var^2]], var3;]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp( // Before comment.
|
||||
[[void func() [[{
|
||||
int var1 = 1;
|
||||
[[[[int var2 = [[[[var1]]^ /*some comment*/ + 41]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
// Empty file.
|
||||
"^",
|
||||
// FIXME: We should get the whole DeclStmt as a range.
|
||||
R"cpp( // Single statement in TU.
|
||||
[[int v = [[1^00]]]];
|
||||
)cpp",
|
||||
// FIXME: No node found associated to the position.
|
||||
R"cpp( // Cursor at end of VarDecl.
|
||||
void func() {
|
||||
int v = 100 + 100^;
|
||||
}
|
||||
)cpp",
|
||||
// FIXME: No node found associated to the position.
|
||||
R"cpp( // Cursor in between spaces.
|
||||
void func() {
|
||||
int v = 100 + ^ 100;
|
||||
}
|
||||
)cpp",
|
||||
// Structs.
|
||||
R"cpp(
|
||||
struct AAA { struct BBB { static int ccc(); };};
|
||||
[[void func() [[{
|
||||
// int x = AAA::BBB::ccc();
|
||||
[[[[int x = [[[[AAA::BBB::c^cc]]()]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp(
|
||||
struct AAA { struct BBB { static int ccc(); };};
|
||||
[[void func() [[{
|
||||
// int x = AAA::BBB::ccc();
|
||||
[[[[int x = [[[[[[[[[[AA^A]]::]]BBB::]]ccc]]()]]]];]]
|
||||
}]]]]
|
||||
)cpp",
|
||||
R"cpp( // Inside struct.
|
||||
struct A { static int a(); };
|
||||
[[struct B {
|
||||
[[static int b() [[{
|
||||
[[return [[[[1^1]] + 2]]]];
|
||||
}]]]]
|
||||
}]];
|
||||
)cpp",
|
||||
// Namespaces.
|
||||
R"cpp(
|
||||
[[namespace nsa {
|
||||
[[namespace nsb {
|
||||
static int ccc();
|
||||
[[void func() [[{
|
||||
// int x = nsa::nsb::ccc();
|
||||
[[[[int x = [[[[nsa::nsb::cc^c]]()]]]];]]
|
||||
}]]]]
|
||||
}]]
|
||||
}]]
|
||||
)cpp",
|
||||
|
||||
};
|
||||
|
||||
for (const char *Test : Tests) {
|
||||
auto T = Annotations(Test);
|
||||
auto AST = TestTU::withCode(T.code()).build();
|
||||
EXPECT_THAT(llvm::cantFail(getSemanticRanges(AST, T.point())),
|
||||
ElementsAreArray(T.ranges()))
|
||||
<< Test;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
Loading…
x
Reference in New Issue
Block a user