2017-12-19 20:23:48 +08:00
|
|
|
//===--- SourceCode.h - Manipulating source code as strings -----*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2017-12-19 20:23:48 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Various code that examines C++ source code without using heavy AST machinery
|
|
|
|
// (and often not even the lexer). To be used sparingly!
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SOURCECODE_H
|
|
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SOURCECODE_H
|
2019-09-09 20:28:44 +08:00
|
|
|
|
2017-12-19 20:23:48 +08:00
|
|
|
#include "Protocol.h"
|
[clangd] Move non-clang base pieces into separate support/ lib. NFCI
Summary:
This enforces layering, reduces a sprawling clangd/ directory, and makes life
easier for embedders.
Reviewers: kbobyrev
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D79014
2020-04-28 23:49:17 +08:00
|
|
|
#include "support/Context.h"
|
2018-08-08 16:59:29 +08:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2019-02-01 05:30:05 +08:00
|
|
|
#include "clang/Basic/LangOptions.h"
|
2018-02-21 10:39:08 +08:00
|
|
|
#include "clang/Basic/SourceLocation.h"
|
2018-11-28 00:08:53 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2019-01-28 22:01:55 +08:00
|
|
|
#include "clang/Format/Format.h"
|
2018-05-11 20:12:08 +08:00
|
|
|
#include "clang/Tooling/Core/Replacement.h"
|
2020-02-28 16:25:40 +08:00
|
|
|
#include "clang/Tooling/Syntax/Tokens.h"
|
2019-01-28 22:01:55 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2019-07-12 19:42:31 +08:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2019-09-09 20:28:44 +08:00
|
|
|
#include "llvm/Support/Error.h"
|
2019-07-12 19:42:31 +08:00
|
|
|
#include "llvm/Support/SHA1.h"
|
2019-09-09 20:28:44 +08:00
|
|
|
#include <string>
|
2017-12-19 20:23:48 +08:00
|
|
|
|
|
|
|
namespace clang {
|
2018-02-21 10:39:08 +08:00
|
|
|
class SourceManager;
|
|
|
|
|
2017-12-19 20:23:48 +08:00
|
|
|
namespace clangd {
|
|
|
|
|
2018-11-28 00:08:53 +08:00
|
|
|
// We tend to generate digests for source codes in a lot of different places.
|
|
|
|
// This represents the type for those digests to prevent us hard coding details
|
|
|
|
// of hashing function at every place that needs to store this information.
|
[clangd] Use xxhash instead of SHA1 for background index file digests.
Summary:
Currently SHA1 is about 10% of our CPU, this patch reduces it to ~1%.
xxhash is a well-defined (stable) non-cryptographic hash optimized for
fast checksums (like crc32).
Collisions shouldn't be a problem, despite the reduced length:
- for actual file content (used to invalidate bg index shards), there
are only two versions that can collide (new shard and old shard).
- for file paths in bg index shard filenames, we would need 2^32 files
with the same filename to expect a collision. Imperfect hashing may
reduce this a bit but it's well beyond what's plausible.
This will invalidate shards on disk (as usual; I bumped the version),
but this time the filenames are changing so the old files will stick
around :-( So this is more expensive than the usual bump, but would be
good to land before the v9 branch when everyone will start using bg index.
Reviewers: kadircet
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D64306
llvm-svn: 365311
2019-07-08 19:33:17 +08:00
|
|
|
using FileDigest = std::array<uint8_t, 8>;
|
2018-11-28 00:08:53 +08:00
|
|
|
FileDigest digest(StringRef Content);
|
|
|
|
Optional<FileDigest> digestFile(const SourceManager &SM, FileID FID);
|
|
|
|
|
2019-03-28 01:47:49 +08:00
|
|
|
// This context variable controls the behavior of functions in this file
|
|
|
|
// that convert between LSP offsets and native clang byte offsets.
|
|
|
|
// If not set, defaults to UTF-16 for backwards-compatibility.
|
|
|
|
extern Key<OffsetEncoding> kCurrentOffsetEncoding;
|
|
|
|
|
2018-10-23 19:51:53 +08:00
|
|
|
// Counts the number of UTF-16 code units needed to represent a string (LSP
|
|
|
|
// specifies string lengths in UTF-16 code units).
|
2019-03-28 01:47:49 +08:00
|
|
|
// Use of UTF-16 may be overridden by kCurrentOffsetEncoding.
|
2018-10-23 19:51:53 +08:00
|
|
|
size_t lspLength(StringRef Code);
|
|
|
|
|
2017-12-19 20:23:48 +08:00
|
|
|
/// Turn a [line, column] pair into an offset in Code.
|
Make positionToOffset return llvm::Expected<size_t>
Summary:
To implement incremental document syncing, we want to verify that the
ranges provided by the front-end are valid. Currently, positionToOffset
deals with invalid Positions by returning 0 or Code.size(), which are
two valid offsets. Instead, return an llvm:Expected<size_t> with an
error if the position is invalid.
According to the LSP, if the character value exceeds the number of
characters of the given line, it should default back to the end of the
line. It makes sense in some contexts to have this behavior, and does
not in other contexts. The AllowColumnsBeyondLineLength parameter
allows to decide what to do in that case, default back to the end of the
line, or return an error.
Reviewers: ilya-biryukov
Subscribers: klimek, ilya-biryukov, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D44673
llvm-svn: 328100
2018-03-21 22:36:46 +08:00
|
|
|
///
|
[clangd] Fix unicode handling, using UTF-16 where LSP requires it.
Summary:
The Language Server Protocol unfortunately mandates that locations in files
be represented by line/column pairs, where the "column" is actually an index
into the UTF-16-encoded text of the line.
(This is because VSCode is written in JavaScript, which is UTF-16-native).
Internally clangd treats source files at UTF-8, the One True Encoding, and
generally deals with byte offsets (though there are exceptions).
Before this patch, conversions between offsets and LSP Position pretended
that Position.character was UTF-8 bytes, which is only true for ASCII lines.
Now we examine the text to convert correctly (but don't actually need to
transcode it, due to some nice details of the encodings).
The updated functions in SourceCode are the blessed way to interact with
the Position.character field, and anything else is likely to be wrong.
So I also updated the other accesses:
- CodeComplete needs a "clang-style" line/column, with column in utf-8 bytes.
This is now converted via Position -> offset -> clang line/column
(a new function is added to SourceCode.h for the second conversion).
- getBeginningOfIdentifier skipped backwards in UTF-16 space, which is will
behave badly when it splits a surrogate pair. Skipping backwards in UTF-8
coordinates gives the lexer a fighting chance of getting this right.
While here, I clarified(?) the logic comments, fixed a bug with identifiers
containing digits, simplified the signature slightly and added a test.
This seems likely to cause problems with editors that have the same bug, and
treat the protocol as if columns are UTF-8 bytes. But we can find and fix those.
Reviewers: hokein
Subscribers: klimek, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D46035
llvm-svn: 331029
2018-04-27 19:59:28 +08:00
|
|
|
/// If P.character exceeds the line length, returns the offset at end-of-line.
|
|
|
|
/// (If !AllowColumnsBeyondLineLength, then returns an error instead).
|
|
|
|
/// If the line number is out of range, returns an error.
|
Make positionToOffset return llvm::Expected<size_t>
Summary:
To implement incremental document syncing, we want to verify that the
ranges provided by the front-end are valid. Currently, positionToOffset
deals with invalid Positions by returning 0 or Code.size(), which are
two valid offsets. Instead, return an llvm:Expected<size_t> with an
error if the position is invalid.
According to the LSP, if the character value exceeds the number of
characters of the given line, it should default back to the end of the
line. It makes sense in some contexts to have this behavior, and does
not in other contexts. The AllowColumnsBeyondLineLength parameter
allows to decide what to do in that case, default back to the end of the
line, or return an error.
Reviewers: ilya-biryukov
Subscribers: klimek, ilya-biryukov, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D44673
llvm-svn: 328100
2018-03-21 22:36:46 +08:00
|
|
|
///
|
|
|
|
/// The returned value is in the range [0, Code.size()].
|
|
|
|
llvm::Expected<size_t>
|
|
|
|
positionToOffset(llvm::StringRef Code, Position P,
|
2019-02-07 23:38:14 +08:00
|
|
|
bool AllowColumnsBeyondLineLength = true);
|
2017-12-19 20:23:48 +08:00
|
|
|
|
|
|
|
/// Turn an offset in Code into a [line, column] pair.
|
[clangd] Fix unicode handling, using UTF-16 where LSP requires it.
Summary:
The Language Server Protocol unfortunately mandates that locations in files
be represented by line/column pairs, where the "column" is actually an index
into the UTF-16-encoded text of the line.
(This is because VSCode is written in JavaScript, which is UTF-16-native).
Internally clangd treats source files at UTF-8, the One True Encoding, and
generally deals with byte offsets (though there are exceptions).
Before this patch, conversions between offsets and LSP Position pretended
that Position.character was UTF-8 bytes, which is only true for ASCII lines.
Now we examine the text to convert correctly (but don't actually need to
transcode it, due to some nice details of the encodings).
The updated functions in SourceCode are the blessed way to interact with
the Position.character field, and anything else is likely to be wrong.
So I also updated the other accesses:
- CodeComplete needs a "clang-style" line/column, with column in utf-8 bytes.
This is now converted via Position -> offset -> clang line/column
(a new function is added to SourceCode.h for the second conversion).
- getBeginningOfIdentifier skipped backwards in UTF-16 space, which is will
behave badly when it splits a surrogate pair. Skipping backwards in UTF-8
coordinates gives the lexer a fighting chance of getting this right.
While here, I clarified(?) the logic comments, fixed a bug with identifiers
containing digits, simplified the signature slightly and added a test.
This seems likely to cause problems with editors that have the same bug, and
treat the protocol as if columns are UTF-8 bytes. But we can find and fix those.
Reviewers: hokein
Subscribers: klimek, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D46035
llvm-svn: 331029
2018-04-27 19:59:28 +08:00
|
|
|
/// The offset must be in range [0, Code.size()].
|
2017-12-19 20:23:48 +08:00
|
|
|
Position offsetToPosition(llvm::StringRef Code, size_t Offset);
|
|
|
|
|
2018-02-21 10:39:08 +08:00
|
|
|
/// Turn a SourceLocation into a [line, column] pair.
|
Make positionToOffset return llvm::Expected<size_t>
Summary:
To implement incremental document syncing, we want to verify that the
ranges provided by the front-end are valid. Currently, positionToOffset
deals with invalid Positions by returning 0 or Code.size(), which are
two valid offsets. Instead, return an llvm:Expected<size_t> with an
error if the position is invalid.
According to the LSP, if the character value exceeds the number of
characters of the given line, it should default back to the end of the
line. It makes sense in some contexts to have this behavior, and does
not in other contexts. The AllowColumnsBeyondLineLength parameter
allows to decide what to do in that case, default back to the end of the
line, or return an error.
Reviewers: ilya-biryukov
Subscribers: klimek, ilya-biryukov, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D44673
llvm-svn: 328100
2018-03-21 22:36:46 +08:00
|
|
|
/// FIXME: This should return an error if the location is invalid.
|
2018-02-21 10:39:08 +08:00
|
|
|
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc);
|
|
|
|
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
/// Return the file location, corresponding to \p P. Note that one should take
|
|
|
|
/// care to avoid comparing the result with expansion locations.
|
|
|
|
llvm::Expected<SourceLocation> sourceLocationInMainFile(const SourceManager &SM,
|
|
|
|
Position P);
|
|
|
|
|
2019-07-19 16:33:39 +08:00
|
|
|
/// Returns true iff \p Loc is inside the main file. This function handles
|
|
|
|
/// file & macro locations. For macro locations, returns iff the macro is being
|
|
|
|
/// expanded inside the main file.
|
|
|
|
///
|
|
|
|
/// The function is usually used to check whether a declaration is inside the
|
|
|
|
/// the main file.
|
|
|
|
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM);
|
|
|
|
|
2019-08-27 16:44:06 +08:00
|
|
|
/// Returns the #include location through which IncludedFIle was loaded.
|
|
|
|
/// Where SM.getIncludeLoc() returns the location of the *filename*, which may
|
|
|
|
/// be in a macro, includeHashLoc() returns the location of the #.
|
|
|
|
SourceLocation includeHashLoc(FileID IncludedFile, const SourceManager &SM);
|
|
|
|
|
2019-08-07 04:25:59 +08:00
|
|
|
/// Returns true if the token at Loc is spelled in the source code.
|
|
|
|
/// This is not the case for:
|
|
|
|
/// * symbols formed via macro concatenation, the spelling location will
|
|
|
|
/// be "<scratch space>"
|
|
|
|
/// * symbols controlled and defined by a compile command-line option
|
|
|
|
/// `-DName=foo`, the spelling location will be "<command line>".
|
|
|
|
bool isSpelledInSource(SourceLocation Loc, const SourceManager &SM);
|
|
|
|
|
2019-02-01 05:30:05 +08:00
|
|
|
/// Turns a token range into a half-open range and checks its correctness.
|
|
|
|
/// The resulting range will have only valid source location on both sides, both
|
|
|
|
/// of which are file locations.
|
|
|
|
///
|
|
|
|
/// File locations always point to a particular offset in a file, i.e. they
|
|
|
|
/// never refer to a location inside a macro expansion. Turning locations from
|
|
|
|
/// macro expansions into file locations is ambiguous - one can use
|
|
|
|
/// SourceManager::{getExpansion|getFile|getSpelling}Loc. This function
|
|
|
|
/// calls SourceManager::getFileLoc on both ends of \p R to do the conversion.
|
|
|
|
///
|
|
|
|
/// User input (e.g. cursor position) is expressed as a file location, so this
|
|
|
|
/// function can be viewed as a way to normalize the ranges used in the clang
|
|
|
|
/// AST so that they are comparable with ranges coming from the user input.
|
|
|
|
llvm::Optional<SourceRange> toHalfOpenFileRange(const SourceManager &Mgr,
|
|
|
|
const LangOptions &LangOpts,
|
|
|
|
SourceRange R);
|
|
|
|
|
|
|
|
/// Returns true iff all of the following conditions hold:
|
|
|
|
/// - start and end locations are valid,
|
|
|
|
/// - start and end locations are file locations from the same file
|
|
|
|
/// (i.e. expansion locations are not taken into account).
|
|
|
|
/// - start offset <= end offset.
|
|
|
|
/// FIXME: introduce a type for source range with this invariant.
|
|
|
|
bool isValidFileRange(const SourceManager &Mgr, SourceRange R);
|
|
|
|
|
|
|
|
/// Returns the source code covered by the source range.
|
|
|
|
/// EXPECTS: isValidFileRange(R) == true.
|
|
|
|
llvm::StringRef toSourceCode(const SourceManager &SM, SourceRange R);
|
|
|
|
|
2018-03-12 23:28:22 +08:00
|
|
|
// Converts a half-open clang source range to an LSP range.
|
|
|
|
// Note that clang also uses closed source ranges, which this can't handle!
|
|
|
|
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R);
|
|
|
|
|
[clangd] Fix unicode handling, using UTF-16 where LSP requires it.
Summary:
The Language Server Protocol unfortunately mandates that locations in files
be represented by line/column pairs, where the "column" is actually an index
into the UTF-16-encoded text of the line.
(This is because VSCode is written in JavaScript, which is UTF-16-native).
Internally clangd treats source files at UTF-8, the One True Encoding, and
generally deals with byte offsets (though there are exceptions).
Before this patch, conversions between offsets and LSP Position pretended
that Position.character was UTF-8 bytes, which is only true for ASCII lines.
Now we examine the text to convert correctly (but don't actually need to
transcode it, due to some nice details of the encodings).
The updated functions in SourceCode are the blessed way to interact with
the Position.character field, and anything else is likely to be wrong.
So I also updated the other accesses:
- CodeComplete needs a "clang-style" line/column, with column in utf-8 bytes.
This is now converted via Position -> offset -> clang line/column
(a new function is added to SourceCode.h for the second conversion).
- getBeginningOfIdentifier skipped backwards in UTF-16 space, which is will
behave badly when it splits a surrogate pair. Skipping backwards in UTF-8
coordinates gives the lexer a fighting chance of getting this right.
While here, I clarified(?) the logic comments, fixed a bug with identifiers
containing digits, simplified the signature slightly and added a test.
This seems likely to cause problems with editors that have the same bug, and
treat the protocol as if columns are UTF-8 bytes. But we can find and fix those.
Reviewers: hokein
Subscribers: klimek, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D46035
llvm-svn: 331029
2018-04-27 19:59:28 +08:00
|
|
|
// Converts an offset to a clang line/column (1-based, columns are bytes).
|
|
|
|
// The offset must be in range [0, Code.size()].
|
|
|
|
// Prefer to use SourceManager if one is available.
|
|
|
|
std::pair<size_t, size_t> offsetToClangLineColumn(llvm::StringRef Code,
|
2019-02-07 23:38:14 +08:00
|
|
|
size_t Offset);
|
[clangd] Fix unicode handling, using UTF-16 where LSP requires it.
Summary:
The Language Server Protocol unfortunately mandates that locations in files
be represented by line/column pairs, where the "column" is actually an index
into the UTF-16-encoded text of the line.
(This is because VSCode is written in JavaScript, which is UTF-16-native).
Internally clangd treats source files at UTF-8, the One True Encoding, and
generally deals with byte offsets (though there are exceptions).
Before this patch, conversions between offsets and LSP Position pretended
that Position.character was UTF-8 bytes, which is only true for ASCII lines.
Now we examine the text to convert correctly (but don't actually need to
transcode it, due to some nice details of the encodings).
The updated functions in SourceCode are the blessed way to interact with
the Position.character field, and anything else is likely to be wrong.
So I also updated the other accesses:
- CodeComplete needs a "clang-style" line/column, with column in utf-8 bytes.
This is now converted via Position -> offset -> clang line/column
(a new function is added to SourceCode.h for the second conversion).
- getBeginningOfIdentifier skipped backwards in UTF-16 space, which is will
behave badly when it splits a surrogate pair. Skipping backwards in UTF-8
coordinates gives the lexer a fighting chance of getting this right.
While here, I clarified(?) the logic comments, fixed a bug with identifiers
containing digits, simplified the signature slightly and added a test.
This seems likely to cause problems with editors that have the same bug, and
treat the protocol as if columns are UTF-8 bytes. But we can find and fix those.
Reviewers: hokein
Subscribers: klimek, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D46035
llvm-svn: 331029
2018-04-27 19:59:28 +08:00
|
|
|
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
/// From "a::b::c", return {"a::b::", "c"}. Scope is empty if there's no
|
|
|
|
/// qualifier.
|
|
|
|
std::pair<llvm::StringRef, llvm::StringRef>
|
|
|
|
splitQualifiedName(llvm::StringRef QName);
|
|
|
|
|
2018-05-11 20:12:08 +08:00
|
|
|
TextEdit replacementToEdit(StringRef Code, const tooling::Replacement &R);
|
|
|
|
|
|
|
|
std::vector<TextEdit> replacementsToEdits(StringRef Code,
|
2019-02-07 23:38:14 +08:00
|
|
|
const tooling::Replacements &Repls);
|
2018-05-11 20:12:08 +08:00
|
|
|
|
2018-08-08 16:59:29 +08:00
|
|
|
TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M,
|
2019-02-07 23:38:14 +08:00
|
|
|
const LangOptions &L);
|
2018-08-08 16:59:29 +08:00
|
|
|
|
2018-12-19 18:46:21 +08:00
|
|
|
/// Get the canonical path of \p F. This means:
|
[clangd] Avoid duplicates in findDefinitions response
Summary:
When compile_commands.json contains some source files expressed as
relative paths, we can get duplicate responses to findDefinitions. The
responses only differ by the URI, which are different versions of the
same file:
"result": [
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/build/../src/first.h"
},
{
...
"uri": "file:///home/emaisin/src/ls-interact/cpp-test/src/first.h"
}
]
In getAbsoluteFilePath, we try to obtain the realpath of the FileEntry
by calling tryGetRealPathName. However, this can fail and return an
empty string. It may be bug a bug in clang, but in any case we should
fall back to computing it ourselves if it happens.
I changed getAbsoluteFilePath so that if tryGetRealPathName succeeds, we
return right away (a real path is always absolute). Otherwise, we try
to build an absolute path, as we did before, but we also call
VFS->getRealPath to make sure to get the canonical path (e.g. without
any ".." in it).
Reviewers: malaperle
Subscribers: hokein, ilya-biryukov, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D48687
llvm-svn: 339483
2018-08-11 06:27:53 +08:00
|
|
|
///
|
|
|
|
/// - Absolute path
|
|
|
|
/// - Symlinks resolved
|
|
|
|
/// - No "." or ".." component
|
|
|
|
/// - No duplicate or trailing directory separator
|
|
|
|
///
|
2018-12-19 18:46:21 +08:00
|
|
|
/// This function should be used when paths needs to be used outside the
|
|
|
|
/// component that generate it, so that paths are normalized as much as
|
|
|
|
/// possible.
|
|
|
|
llvm::Optional<std::string> getCanonicalPath(const FileEntry *F,
|
2019-02-07 23:38:14 +08:00
|
|
|
const SourceManager &SourceMgr);
|
2018-08-13 16:23:01 +08:00
|
|
|
|
2019-05-06 16:39:17 +08:00
|
|
|
/// Choose the clang-format style we should apply to a certain file.
|
|
|
|
/// This will usually use FS to look for .clang-format directories.
|
|
|
|
/// FIXME: should we be caching the .clang-format file search?
|
|
|
|
/// This uses format::DefaultFormatStyle and format::DefaultFallbackStyle,
|
|
|
|
/// though the latter may have been overridden in main()!
|
2019-01-28 22:01:55 +08:00
|
|
|
format::FormatStyle getFormatStyleForFile(llvm::StringRef File,
|
|
|
|
llvm::StringRef Content,
|
|
|
|
llvm::vfs::FileSystem *FS);
|
|
|
|
|
2019-09-09 20:28:44 +08:00
|
|
|
/// Cleanup and format the given replacements.
|
2019-02-06 23:24:50 +08:00
|
|
|
llvm::Expected<tooling::Replacements>
|
|
|
|
cleanupAndFormat(StringRef Code, const tooling::Replacements &Replaces,
|
|
|
|
const format::FormatStyle &Style);
|
|
|
|
|
2019-09-09 20:28:44 +08:00
|
|
|
/// A set of edits generated for a single file. Can verify whether it is safe to
|
|
|
|
/// apply these edits to a code block.
|
|
|
|
struct Edit {
|
|
|
|
tooling::Replacements Replacements;
|
|
|
|
std::string InitialCode;
|
|
|
|
|
|
|
|
Edit(llvm::StringRef Code, tooling::Replacements Reps)
|
|
|
|
: Replacements(std::move(Reps)), InitialCode(Code) {}
|
|
|
|
|
|
|
|
/// Returns the file contents after changes are applied.
|
|
|
|
llvm::Expected<std::string> apply() const;
|
|
|
|
|
|
|
|
/// Represents Replacements as TextEdits that are available for use in LSP.
|
|
|
|
std::vector<TextEdit> asTextEdits() const;
|
|
|
|
|
|
|
|
/// Checks whether the Replacements are applicable to given Code.
|
|
|
|
bool canApplyTo(llvm::StringRef Code) const;
|
|
|
|
};
|
2019-10-23 20:40:20 +08:00
|
|
|
/// A mapping from absolute file path (the one used for accessing the underlying
|
|
|
|
/// VFS) to edits.
|
|
|
|
using FileEdits = llvm::StringMap<Edit>;
|
2019-09-09 20:28:44 +08:00
|
|
|
|
|
|
|
/// Formats the edits and code around it according to Style. Changes
|
|
|
|
/// Replacements to formatted ones if succeeds.
|
|
|
|
llvm::Error reformatEdit(Edit &E, const format::FormatStyle &Style);
|
|
|
|
|
2019-04-11 17:36:36 +08:00
|
|
|
/// Collects identifiers with counts in the source code.
|
|
|
|
llvm::StringMap<unsigned> collectIdentifiers(llvm::StringRef Content,
|
|
|
|
const format::FormatStyle &Style);
|
|
|
|
|
2019-10-30 20:21:47 +08:00
|
|
|
/// Collects all ranges of the given identifier in the source code.
|
|
|
|
std::vector<Range> collectIdentifierRanges(llvm::StringRef Identifier,
|
|
|
|
llvm::StringRef Content,
|
|
|
|
const LangOptions &LangOpts);
|
|
|
|
|
2019-05-06 18:25:10 +08:00
|
|
|
/// Collects words from the source code.
|
|
|
|
/// Unlike collectIdentifiers:
|
|
|
|
/// - also finds text in comments:
|
|
|
|
/// - splits text into words
|
|
|
|
/// - drops stopwords like "get" and "for"
|
|
|
|
llvm::StringSet<> collectWords(llvm::StringRef Content);
|
|
|
|
|
2020-03-03 05:45:25 +08:00
|
|
|
// Something that looks like a word in the source code.
|
|
|
|
// Could be a "real" token that's "live" in the AST, a spelled token consumed by
|
|
|
|
// the preprocessor, or part of a spelled token (e.g. word in a comment).
|
|
|
|
struct SpelledWord {
|
|
|
|
// (Spelling) location of the start of the word.
|
|
|
|
SourceLocation Location;
|
|
|
|
// The range of the word itself, excluding any quotes.
|
|
|
|
// This is a subrange of the file buffer.
|
|
|
|
llvm::StringRef Text;
|
|
|
|
// Whether this word is likely to refer to an identifier. True if:
|
|
|
|
// - the word is a spelled identifier token
|
|
|
|
// - Text is identifier-like (e.g. "foo_bar")
|
|
|
|
// - Text is surrounded by backticks (e.g. Foo in "// returns `Foo`")
|
|
|
|
bool LikelyIdentifier = false;
|
|
|
|
// Set if the word is contained in a token spelled in the file.
|
|
|
|
// (This should always be true, but comments aren't retained by TokenBuffer).
|
|
|
|
const syntax::Token *PartOfSpelledToken = nullptr;
|
|
|
|
// Set if the word is exactly a token spelled in the file.
|
|
|
|
const syntax::Token *SpelledToken = nullptr;
|
|
|
|
// Set if the word is a token spelled in the file, and that token survives
|
|
|
|
// preprocessing to emit an expanded token spelled the same way.
|
|
|
|
const syntax::Token *ExpandedToken = nullptr;
|
|
|
|
|
|
|
|
// Find the unique word that contains SpelledLoc or starts/ends there.
|
|
|
|
static llvm::Optional<SpelledWord> touching(SourceLocation SpelledLoc,
|
|
|
|
const syntax::TokenBuffer &TB,
|
|
|
|
const LangOptions &LangOpts);
|
|
|
|
};
|
|
|
|
|
2019-04-26 15:45:49 +08:00
|
|
|
/// Heuristically determine namespaces visible at a point, without parsing Code.
|
|
|
|
/// This considers using-directives and enclosing namespace-declarations that
|
|
|
|
/// are visible (and not obfuscated) in the file itself (not headers).
|
|
|
|
/// Code should be truncated at the point of interest.
|
|
|
|
///
|
|
|
|
/// The returned vector is always non-empty.
|
|
|
|
/// - The first element is the namespace that encloses the point: a declaration
|
|
|
|
/// near the point would be within this namespace.
|
|
|
|
/// - The elements are the namespaces in scope at the point: an unqualified
|
|
|
|
/// lookup would search within these namespaces.
|
|
|
|
///
|
|
|
|
/// Using directives are resolved against all enclosing scopes, but no other
|
|
|
|
/// namespace directives.
|
|
|
|
///
|
|
|
|
/// example:
|
|
|
|
/// using namespace a;
|
|
|
|
/// namespace foo {
|
|
|
|
/// using namespace b;
|
|
|
|
///
|
|
|
|
/// visibleNamespaces are {"foo::", "", "a::", "b::", "foo::b::"}, not "a::b::".
|
|
|
|
std::vector<std::string> visibleNamespaces(llvm::StringRef Code,
|
2020-03-06 08:03:26 +08:00
|
|
|
const LangOptions &LangOpts);
|
2019-04-26 15:45:49 +08:00
|
|
|
|
2019-09-25 17:35:38 +08:00
|
|
|
/// Represents locations that can accept a definition.
|
|
|
|
struct EligibleRegion {
|
|
|
|
/// Namespace that owns all of the EligiblePoints, e.g.
|
|
|
|
/// namespace a{ namespace b {^ void foo();^} }
|
|
|
|
/// It will be “a::b” for both carrot locations.
|
|
|
|
std::string EnclosingNamespace;
|
|
|
|
/// Offsets into the code marking eligible points to insert a function
|
|
|
|
/// definition.
|
|
|
|
std::vector<Position> EligiblePoints;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Returns most eligible region to insert a definition for \p
|
|
|
|
/// FullyQualifiedName in the \p Code.
|
|
|
|
/// Pseudo parses \pCode under the hood to determine namespace decls and
|
|
|
|
/// possible insertion points. Choses the region that matches the longest prefix
|
|
|
|
/// of \p FullyQualifiedName. Returns EOF if there are no shared namespaces.
|
|
|
|
/// \p FullyQualifiedName should not contain anonymous namespaces.
|
|
|
|
EligibleRegion getEligiblePoints(llvm::StringRef Code,
|
|
|
|
llvm::StringRef FullyQualifiedName,
|
2020-03-06 08:03:26 +08:00
|
|
|
const LangOptions &LangOpts);
|
2019-09-25 17:35:38 +08:00
|
|
|
|
2019-07-01 17:26:48 +08:00
|
|
|
struct DefinedMacro {
|
|
|
|
llvm::StringRef Name;
|
|
|
|
const MacroInfo *Info;
|
|
|
|
};
|
2020-02-28 16:25:40 +08:00
|
|
|
/// Gets the macro referenced by \p SpelledTok. It must be a spelled token
|
|
|
|
/// aligned to the beginning of an identifier.
|
|
|
|
llvm::Optional<DefinedMacro> locateMacroAt(const syntax::Token &SpelledTok,
|
2019-07-01 17:26:48 +08:00
|
|
|
Preprocessor &PP);
|
|
|
|
|
[clangd] Add isHeaderFile helper.
Summary:
we have a few places using `ASTCtx.getLangOpts().IsHeaderFile` to
determine a header file, but it relies on "-x c-header" compiler flag,
if the compilation command doesn't have this flag, we will get a false
positive. We are encountering this issue in bazel build system.
To solve this problem, we infer the file from file name, actual changes will
come in follow-ups.
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D70235
2019-11-13 23:30:07 +08:00
|
|
|
/// Infers whether this is a header from the FileName and LangOpts (if
|
|
|
|
/// presents).
|
|
|
|
bool isHeaderFile(llvm::StringRef FileName,
|
|
|
|
llvm::Optional<LangOptions> LangOpts = llvm::None);
|
|
|
|
|
2020-02-05 19:03:29 +08:00
|
|
|
/// Returns true if the given location is in a generated protobuf file.
|
|
|
|
bool isProtoFile(SourceLocation Loc, const SourceManager &SourceMgr);
|
|
|
|
|
2017-12-19 20:23:48 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|
|
|
|
#endif
|