15 #include "clang/AST/ASTContext.h" 16 #include "clang/Basic/LangOptions.h" 17 #include "clang/Basic/SourceLocation.h" 18 #include "clang/Basic/SourceManager.h" 19 #include "clang/Basic/TokenKinds.h" 20 #include "clang/Driver/Types.h" 21 #include "clang/Format/Format.h" 22 #include "clang/Lex/Lexer.h" 23 #include "clang/Lex/Preprocessor.h" 24 #include "clang/Lex/Token.h" 25 #include "clang/Tooling/Core/Replacement.h" 26 #include "llvm/ADT/ArrayRef.h" 27 #include "llvm/ADT/None.h" 28 #include "llvm/ADT/STLExtras.h" 29 #include "llvm/ADT/StringExtras.h" 30 #include "llvm/ADT/StringMap.h" 31 #include "llvm/ADT/StringRef.h" 32 #include "llvm/Support/Compiler.h" 33 #include "llvm/Support/Errc.h" 34 #include "llvm/Support/Error.h" 35 #include "llvm/Support/ErrorHandling.h" 36 #include "llvm/Support/LineIterator.h" 37 #include "llvm/Support/MemoryBuffer.h" 38 #include "llvm/Support/Path.h" 39 #include "llvm/Support/SHA1.h" 40 #include "llvm/Support/VirtualFileSystem.h" 41 #include "llvm/Support/xxhash.h" 56 template <
typename Callback>
60 for (
size_t I = 0; I < U8.size();) {
61 unsigned char C =
static_cast<unsigned char>(U8[I]);
62 if (LLVM_LIKELY(!(C & 0x80))) {
69 size_t UTF8Length = llvm::countLeadingOnes(C);
72 assert((UTF8Length >= 2 && UTF8Length <= 4) &&
73 "Invalid UTF-8, or transcoding bug?");
77 if (CB(UTF8Length, UTF8Length == 4 ? 2 : 1))
114 llvm_unreachable(
"unsupported encoding");
117 if (Result > U8.size()) {
150 llvm_unreachable(
"unsupported encoding");
156 bool AllowColumnsBeyondLineLength) {
158 return llvm::make_error<llvm::StringError>(
159 llvm::formatv(
"Line value can't be negative ({0})", P.
line),
160 llvm::errc::invalid_argument);
162 return llvm::make_error<llvm::StringError>(
163 llvm::formatv(
"Character value can't be negative ({0})", P.
character),
164 llvm::errc::invalid_argument);
165 size_t StartOfLine = 0;
166 for (
int I = 0; I != P.
line; ++I) {
167 size_t NextNL = Code.find(
'\n', StartOfLine);
168 if (NextNL == llvm::StringRef::npos)
169 return llvm::make_error<llvm::StringError>(
170 llvm::formatv(
"Line value is out of range ({0})", P.
line),
171 llvm::errc::invalid_argument);
172 StartOfLine = NextNL + 1;
175 Code.substr(StartOfLine).take_until([](
char C) {
return C ==
'\n'; });
180 if (!Valid && !AllowColumnsBeyondLineLength)
181 return llvm::make_error<llvm::StringError>(
182 llvm::formatv(
"{0} offset {1} is invalid for line {2}",
lspEncoding(),
184 llvm::errc::invalid_argument);
185 return StartOfLine + ByteInLine;
189 Offset = std::min(Code.size(),
Offset);
190 llvm::StringRef Before = Code.substr(0, Offset);
191 int Lines = Before.count(
'\n');
192 size_t PrevNL = Before.rfind(
'\n');
193 size_t StartOfLine = (PrevNL == llvm::StringRef::npos) ? 0 : (PrevNL + 1);
204 std::tie(FID, Offset) = SM.getDecomposedSpellingLoc(Loc);
206 P.
line =
static_cast<int>(SM.getLineNumber(FID, Offset)) - 1;
207 bool Invalid =
false;
208 llvm::StringRef
Code = SM.getBufferData(FID, &Invalid);
210 auto ColumnInBytes = SM.getColumnNumber(FID, Offset) - 1;
211 auto LineSoFar = Code.substr(Offset - ColumnInBytes, ColumnInBytes);
218 if (Loc.isMacroID()) {
219 std::string PrintLoc = SM.getSpellingLoc(Loc).printToString(SM);
220 if (llvm::StringRef(PrintLoc).startswith(
"<scratch") ||
221 llvm::StringRef(PrintLoc).startswith(
"<command line>"))
228 const LangOptions &LangOpts,
229 SourceLocation TokLoc) {
230 if (!TokLoc.isValid())
232 SourceLocation End = Lexer::getLocForEndOfToken(TokLoc, 0, SM, LangOpts);
235 return halfOpenToRange(SM, CharSourceRange::getCharRange(TokLoc, End));
242 bool isOverloadedOperator(
const Token &Tok) {
243 switch (Tok.getKind()) {
244 #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemOnly) \ 246 #define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemOnly) 247 #include "clang/Basic/OperatorKinds.def" 256 TokenFlavor getTokenFlavor(SourceLocation
Loc,
const SourceManager &SM,
257 const LangOptions &LangOpts) {
259 Tok.setKind(tok::NUM_TOKENS);
260 if (Lexer::getRawToken(Loc, Tok, SM, LangOpts,
266 if (Tok.is(tok::TokenKind::NUM_TOKENS))
268 if (Tok.is(tok::TokenKind::raw_identifier))
270 if (isOverloadedOperator(Tok))
278 const SourceManager &SM,
279 const LangOptions &LangOpts) {
280 FileID FID = SM.getMainFileID();
283 log(
"getBeginningOfIdentifier: {0}",
Offset.takeError());
284 return SourceLocation();
297 SourceLocation InputLoc = SM.getComposedLoc(FID, *
Offset);
300 SourceLocation Before = SM.getComposedLoc(FID, *
Offset - 1);
301 SourceLocation BeforeTokBeginning =
302 Lexer::GetBeginningOfToken(Before, SM, LangOpts);
303 TokenFlavor BeforeKind = getTokenFlavor(BeforeTokBeginning, SM, LangOpts);
305 SourceLocation CurrentTokBeginning =
306 Lexer::GetBeginningOfToken(InputLoc, SM, LangOpts);
307 TokenFlavor CurrentKind = getTokenFlavor(CurrentTokBeginning, SM, LangOpts);
310 if (BeforeTokBeginning == CurrentTokBeginning) {
313 return CurrentTokBeginning;
319 if (BeforeKind == Whitespace)
320 return CurrentTokBeginning;
321 if (CurrentKind == Whitespace)
322 return BeforeTokBeginning;
327 return CurrentTokBeginning;
329 return BeforeTokBeginning;
332 return CurrentTokBeginning;
334 return BeforeTokBeginning;
341 if (!R.getBegin().isValid() || !R.getEnd().isValid())
345 size_t BeginOffset = 0;
346 std::tie(BeginFID, BeginOffset) = Mgr.getDecomposedLoc(R.getBegin());
349 size_t EndOffset = 0;
350 std::tie(EndFID, EndOffset) = Mgr.getDecomposedLoc(R.getEnd());
352 return BeginFID.isValid() && BeginFID == EndFID && BeginOffset <= EndOffset;
360 size_t BeginOffset = 0;
361 std::tie(BeginFID, BeginOffset) = Mgr.getDecomposedLoc(R.getBegin());
362 size_t EndOffset = Mgr.getFileOffset(R.getEnd());
366 std::tie(LFid, LOffset) = Mgr.getDecomposedLoc(L);
367 return BeginFID == LFid && BeginOffset <= LOffset && LOffset < EndOffset;
376 assert(SM.getLocForEndOfFile(IncludedFile).isFileID());
377 FileID IncludingFile;
379 std::tie(IncludingFile, Offset) =
380 SM.getDecomposedExpansionLoc(SM.getIncludeLoc(IncludedFile));
381 bool Invalid =
false;
382 llvm::StringRef Buf = SM.getBufferData(IncludingFile, &Invalid);
384 return SourceLocation();
388 assert(Offset < Buf.size());
390 if (Buf[Offset] ==
'#')
391 return SM.getComposedLoc(IncludingFile, Offset);
392 if (Buf[Offset] ==
'\n' || Offset == 0)
393 return SourceLocation();
398 const LangOptions &LangOpts) {
400 if (Lexer::getRawToken(Loc, TheTok, SM, LangOpts))
407 if (TheTok.is(tok::greatergreater))
409 return TheTok.getLength();
414 const SourceManager &SM,
415 const LangOptions &LangOpts) {
417 return BeginLoc.getLocWithOffset(Len ? Len - 1 : 0);
422 const SourceManager &SM,
423 const LangOptions &LangOpts) {
424 return EndLoc.getLocWithOffset(
430 const LangOptions &LangOpts) {
431 if (!Range.isTokenRange())
433 return Range.getAsRange();
439 const SourceManager &SM,
440 const LangOptions &LangOpts) {
441 SourceLocation Begin =
442 SM.isBeforeInTranslationUnit(R1.getBegin(), R2.getBegin())
450 return SourceRange(Begin, End);
457 const LangOptions &LangOpts) {
459 if (SM.isWrittenInSameFile(R.getBegin(), R.getEnd()))
462 llvm::DenseMap<FileID, SourceLocation> BeginExpansions;
463 for (SourceLocation Begin = R.getBegin(); Begin.isValid();
464 Begin = Begin.isFileID()
466 : SM.getImmediateExpansionRange(Begin).getBegin()) {
467 BeginExpansions[SM.getFileID(Begin)] = Begin;
471 for (SourceLocation End = R.getEnd(); End.isValid();
476 auto It = BeginExpansions.find(SM.getFileID(End));
477 if (It != BeginExpansions.end()) {
478 if (SM.getFileOffset(It->second) > SM.getFileOffset(End))
479 return SourceLocation();
480 return {It->second, End};
483 return SourceRange();
490 const LangOptions &LangOpts) {
492 toTokenRange(SM.getImmediateExpansionRange(Loc), SM, LangOpts), SM,
507 const SourceManager &SM,
508 const LangOptions &LangOpts) {
509 SourceRange FileRange =
Loc;
510 while (!FileRange.getBegin().isFileID()) {
511 if (SM.isMacroArgExpansion(FileRange.getBegin())) {
513 SM.getImmediateSpellingLoc(FileRange.getBegin()),
514 SM.getImmediateSpellingLoc(FileRange.getEnd()), SM, LangOpts);
515 assert(SM.isWrittenInSameFile(FileRange.getBegin(), FileRange.getEnd()));
517 SourceRange ExpansionRangeForBegin =
519 SourceRange ExpansionRangeForEnd =
521 if (ExpansionRangeForBegin.isInvalid() ||
522 ExpansionRangeForEnd.isInvalid())
523 return SourceRange();
524 assert(SM.isWrittenInSameFile(ExpansionRangeForBegin.getBegin(),
525 ExpansionRangeForEnd.getBegin()) &&
526 "Both Expansion ranges should be in same file.");
527 FileRange =
unionTokenRange(ExpansionRangeForBegin, ExpansionRangeForEnd,
535 return Loc.isValid() && SM.isWrittenInMainFile(SM.getExpansionLoc(Loc));
539 const LangOptions &LangOpts,
553 Result.setEnd(Result.getEnd().getLocWithOffset(TokLen));
562 bool Invalid =
false;
563 auto *Buf = SM.getBuffer(SM.getFileID(R.getBegin()), &Invalid);
566 size_t BeginOffset = SM.getFileOffset(R.getBegin());
567 size_t EndOffset = SM.getFileOffset(R.getEnd());
568 return Buf->getBuffer().substr(BeginOffset, EndOffset - BeginOffset);
573 llvm::StringRef
Code = SM.getBuffer(SM.getMainFileID())->getBuffer();
577 return Offset.takeError();
578 return SM.getLocForStartOfFile(SM.getMainFileID()).getLocWithOffset(*
Offset);
591 Offset = std::min(Code.size(),
Offset);
592 llvm::StringRef Before = Code.substr(0, Offset);
593 int Lines = Before.count(
'\n');
594 size_t PrevNL = Before.rfind(
'\n');
595 size_t StartOfLine = (PrevNL == llvm::StringRef::npos) ? 0 : (PrevNL + 1);
596 return {Lines + 1, Offset - StartOfLine + 1};
600 size_t Pos = QName.rfind(
"::");
601 if (Pos == llvm::StringRef::npos)
602 return {llvm::StringRef(), QName};
603 return {QName.substr(0, Pos + 2), QName.substr(Pos + 2)};
607 const tooling::Replacement &R) {
608 Range ReplacementRange = {
611 return {ReplacementRange, R.getReplacementText()};
615 const tooling::Replacements &Repls) {
616 std::vector<TextEdit> Edits;
617 for (
const auto &R : Repls)
623 const SourceManager &SourceMgr) {
627 llvm::SmallString<128> FilePath = F->getName();
628 if (!llvm::sys::path::is_absolute(FilePath)) {
630 SourceMgr.getFileManager().getVirtualFileSystem().makeAbsolute(
632 elog(
"Could not turn relative path '{0}' to absolute: {1}", FilePath,
649 if (
auto Dir = SourceMgr.getFileManager().getDirectory(
650 llvm::sys::path::parent_path(FilePath))) {
651 llvm::SmallString<128> RealPath;
652 llvm::StringRef DirName = SourceMgr.getFileManager().getCanonicalName(*Dir);
653 llvm::sys::path::append(RealPath, DirName,
654 llvm::sys::path::filename(FilePath));
655 return RealPath.str().str();
658 return FilePath.str().str();
662 const LangOptions &L) {
666 Result.
newText = FixIt.CodeToInsert;
676 uint64_t Hash{llvm::xxHash64(Content)};
678 for (
unsigned I = 0; I < Result.size(); ++I) {
679 Result[I] = uint8_t(Hash);
685 llvm::Optional<FileDigest>
digestFile(
const SourceManager &SM, FileID FID) {
686 bool Invalid =
false;
687 llvm::StringRef Content = SM.getBufferData(FID, &Invalid);
694 llvm::StringRef Content,
695 llvm::vfs::FileSystem *
FS) {
696 auto Style = format::getStyle(format::DefaultFormatStyle, File,
697 format::DefaultFallbackStyle, Content, FS);
699 log(
"getStyle() failed for file {0}: {1}. Fallback is LLVM style.", File,
701 Style = format::getLLVMStyle();
706 llvm::Expected<tooling::Replacements>
709 auto CleanReplaces = cleanupAroundReplacements(Code, Replaces, Style);
711 return CleanReplaces;
712 return formatReplacements(Code, std::move(*CleanReplaces), Style);
716 lex(llvm::StringRef
Code,
const LangOptions &LangOpts,
717 llvm::function_ref<
void(
const clang::Token &,
const SourceManager &SM)>
720 std::string NullTerminatedCode = Code.str();
721 SourceManagerForFile FileSM(
"dummy.cpp", NullTerminatedCode);
722 auto &SM = FileSM.get();
723 auto FID = SM.getMainFileID();
725 Lexer Lex(FID, SM.getBuffer(FID), SM, LangOpts);
728 while (!Lex.LexFromRawLexer(Tok))
737 llvm::StringMap<unsigned> Identifiers;
738 auto LangOpt = format::getFormattingLangOpts(Style);
739 lex(Content, LangOpt, [&](
const clang::Token &Tok,
const SourceManager &) {
740 if (Tok.getKind() == tok::raw_identifier)
741 ++Identifiers[Tok.getRawIdentifier()];
747 llvm::StringRef Content,
748 const LangOptions &LangOpts) {
749 std::vector<Range> Ranges;
750 lex(Content, LangOpts, [&](
const clang::Token &Tok,
const SourceManager &SM) {
751 if (Tok.getKind() != tok::raw_identifier)
753 if (Tok.getRawIdentifier() != Identifier)
758 Ranges.push_back(*
Range);
764 struct NamespaceEvent {
775 void parseNamespaceEvents(llvm::StringRef Code,
777 llvm::function_ref<
void(NamespaceEvent)>
Callback) {
780 std::vector<std::string> Enclosing;
782 std::vector<bool> BraceStack;
794 NamespaceEvent
Event;
795 lex(Code, format::getFormattingLangOpts(Style),
796 [&](
const clang::Token &Tok,
const SourceManager &SM) {
798 switch (Tok.getKind()) {
799 case tok::raw_identifier:
803 case UsingNamespaceName:
804 NSName.append(Tok.getRawIdentifier());
805 State = UsingNamespaceName;
809 NSName.append(Tok.getRawIdentifier());
810 State = NamespaceName;
814 (Tok.getRawIdentifier() ==
"namespace") ? UsingNamespace : Default;
818 if (Tok.getRawIdentifier() ==
"namespace")
820 else if (Tok.getRawIdentifier() ==
"using")
825 case tok::coloncolon:
829 case UsingNamespaceName:
831 State = UsingNamespaceName;
835 State = NamespaceName;
846 if (State == NamespaceName) {
848 BraceStack.push_back(
true);
849 Enclosing.push_back(NSName);
850 Event.Trigger = NamespaceEvent::BeginNamespace;
856 BraceStack.push_back(
false);
862 if (!BraceStack.empty()) {
863 if (BraceStack.back()) {
865 Enclosing.pop_back();
866 Event.Trigger = NamespaceEvent::EndNamespace;
870 BraceStack.pop_back();
874 if (State == UsingNamespaceName) {
876 Event.Trigger = NamespaceEvent::UsingDirective;
877 Event.Payload = std::move(NSName);
890 llvm::SmallVector<llvm::StringRef, 8> ancestorNamespaces(llvm::StringRef NS) {
891 llvm::SmallVector<llvm::StringRef, 8>
Results;
892 Results.push_back(NS.take_front(0));
893 NS.split(Results,
"::", -1,
false);
894 for (llvm::StringRef &R : Results)
895 R = NS.take_front(R.end() - NS.begin());
905 llvm::StringMap<llvm::StringSet<>> UsingDirectives;
907 parseNamespaceEvents(Code, Style, [&](NamespaceEvent
Event) {
908 llvm::StringRef NS = Event.Payload;
909 switch (Event.Trigger) {
910 case NamespaceEvent::BeginNamespace:
911 case NamespaceEvent::EndNamespace:
912 Current = std::move(Event.Payload);
914 case NamespaceEvent::UsingDirective:
915 if (NS.consume_front(
"::"))
916 UsingDirectives[Current].insert(NS);
918 for (llvm::StringRef Enclosing : ancestorNamespaces(Current)) {
919 if (Enclosing.empty())
920 UsingDirectives[Current].insert(NS);
922 UsingDirectives[Current].insert((Enclosing +
"::" + NS).str());
929 std::vector<std::string> Found;
930 for (llvm::StringRef Enclosing : ancestorNamespaces(Current)) {
931 Found.push_back(Enclosing);
932 auto It = UsingDirectives.find(Enclosing);
933 if (It != UsingDirectives.end())
934 for (
const auto &Used : It->second)
935 Found.push_back(Used.getKey());
938 llvm::sort(Found, [&](
const std::string &LHS,
const std::string &RHS) {
945 Found.erase(std::unique(Found.begin(), Found.end()), Found.end());
953 static constexpr
int MinWordLength = 4;
955 std::vector<CharRole> Roles(Content.size());
958 llvm::StringSet<> Result;
959 llvm::SmallString<256>
Word;
961 if (Word.size() >= MinWordLength) {
963 C = llvm::toLower(C);
968 for (
unsigned I = 0; I < Content.size(); ++I) {
974 Word.push_back(Content[I]);
989 const auto &SM = PP.getSourceManager();
990 const auto &LangOpts = PP.getLangOpts();
992 if (Lexer::getRawToken(SM.getSpellingLoc(Loc), Result, SM, LangOpts,
false))
994 if (Result.is(tok::raw_identifier))
995 PP.LookUpIdentifierInfo(Result);
996 IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
997 if (!IdentifierInfo || !IdentifierInfo->hadMacroDefinition())
1000 std::pair<FileID, unsigned int> DecLoc = SM.getDecomposedExpansionLoc(Loc);
1003 SourceLocation BeforeSearchedLocation =
1004 SM.getMacroArgExpandedLocation(SM.getLocForStartOfFile(DecLoc.first)
1005 .getLocWithOffset(DecLoc.second - 1));
1006 MacroDefinition MacroDef =
1007 PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
1008 if (
auto *MI = MacroDef.getMacroInfo())
1014 return tooling::applyAllReplacements(InitialCode, Replacements);
1024 auto LHS = llvm::MemoryBuffer::getMemBuffer(Code);
1025 llvm::line_iterator LHSIt(*LHS,
false);
1027 auto RHS = llvm::MemoryBuffer::getMemBuffer(InitialCode);
1028 llvm::line_iterator RHSIt(*RHS,
false);
1034 while (!LHSIt.is_at_eof() && !RHSIt.is_at_eof()) {
1035 if (*LHSIt != *RHSIt)
1044 while (!LHSIt.is_at_eof()) {
1045 if (!LHSIt->empty())
1049 while (!RHSIt.is_at_eof()) {
1050 if (!RHSIt->empty())
1061 return NewEdits.takeError();
1062 return llvm::Error::success();
1066 llvm::StringRef FullyQualifiedName,
1070 std::vector<std::string> Enclosing = {
""};
1074 parseNamespaceEvents(Code, Style, [&](NamespaceEvent
Event) {
1077 if (Event.Trigger == NamespaceEvent::UsingDirective)
1080 if (!Event.Payload.empty())
1081 Event.Payload.append(
"::");
1083 std::string CurrentNamespace;
1084 if (Event.Trigger == NamespaceEvent::BeginNamespace) {
1085 Enclosing.emplace_back(std::move(Event.Payload));
1086 CurrentNamespace = Enclosing.back();
1089 ++Event.Pos.character;
1093 CurrentNamespace = std::move(Enclosing.back());
1094 Enclosing.pop_back();
1095 assert(Enclosing.back() == Event.Payload);
1099 if (!FullyQualifiedName.startswith(CurrentNamespace))
1119 llvm::Optional<LangOptions> LangOpts) {
1122 if (LangOpts && LangOpts->IsHeaderFile)
1124 namespace types = clang::driver::types;
1125 auto Lang = types::lookupTypeForExtension(
1126 llvm::sys::path::extension(FileName).substr(1));
1127 return Lang != types::TY_INVALID && types::onlyPrecompileType(Lang);
SourceLocation Loc
'#' location in the include directive
static SourceRange getExpansionTokenRangeInSameFile(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
llvm::StringSet collectWords(llvm::StringRef Content)
Collects words from the source code.
llvm::Expected< tooling::Replacements > cleanupAndFormat(StringRef Code, const tooling::Replacements &Replaces, const format::FormatStyle &Style)
Cleanup and format the given replacements.
Position start
The range's start position.
static SourceRange rangeInCommonFile(SourceRange R, const SourceManager &SM, const LangOptions &LangOpts)
size_t lspLength(llvm::StringRef Code)
std::array< uint8_t, 8 > FileDigest
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
static SourceRange unionTokenRange(SourceRange R1, SourceRange R2, const SourceManager &SM, const LangOptions &LangOpts)
llvm::Expected< std::string > apply() const
Returns the file contents after changes are applied.
An Event<T> allows events of type T to be broadcast to listeners.
SourceLocation getBeginningOfIdentifier(const Position &Pos, const SourceManager &SM, const LangOptions &LangOpts)
Get the beginning SourceLocation at a specified Pos in the main file.
bool halfOpenRangeContains(const SourceManager &Mgr, SourceRange R, SourceLocation L)
Returns true iff L is contained in R.
std::vector< CodeCompletionResult > Results
Values in a Context are indexed by typed keys.
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Documents should not be synced at all.
bool halfOpenRangeTouches(const SourceManager &Mgr, SourceRange R, SourceLocation L)
Returns true iff L is contained in R or L is equal to the end point of R.
void elog(const char *Fmt, Ts &&... Vals)
bool isSpelledInSource(SourceLocation Loc, const SourceManager &SM)
Returns true if the token at Loc is spelled in the source code.
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const format::FormatStyle &Style)
Heuristically determine namespaces visible at a point, without parsing Code.
bool isRangeConsecutive(const Range &Left, const Range &Right)
bool canApplyTo(llvm::StringRef Code) const
Checks whether the Replacements are applicable to given Code.
bool isValidFileRange(const SourceManager &Mgr, SourceRange R)
Returns true iff all of the following conditions hold:
const Type * get(const Key< Type > &Key) const
Get data stored for a typed Key.
std::pair< size_t, size_t > offsetToClangLineColumn(llvm::StringRef Code, size_t Offset)
TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M, const LangOptions &L)
std::string newText
The string to be inserted.
Position offsetToPosition(llvm::StringRef Code, size_t Offset)
Turn an offset in Code into a [line, column] pair.
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Range range
The range of the text document to be manipulated.
std::string EnclosingNamespace
Namespace that owns all of the EligiblePoints, e.g.
llvm::unique_function< void()> Action
void log(const char *Fmt, Ts &&... Vals)
static size_t measureUnits(llvm::StringRef U8, int Units, OffsetEncoding Enc, bool &Valid)
EligibleRegion getEligiblePoints(llvm::StringRef Code, llvm::StringRef FullyQualifiedName, const format::FormatStyle &Style)
Returns most eligible region to insert a definition for FullyQualifiedName in the Code...
static SourceRange toTokenRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
static const Context & current()
Returns the context for the current thread, creating it if needed.
enum clang::clangd::@771::NamespaceEvent::@3 Trigger
Key< OffsetEncoding > kCurrentOffsetEncoding
CharTypeSet calculateRoles(llvm::StringRef Text, llvm::MutableArrayRef< CharRole > Roles)
static void lex(llvm::StringRef Code, const LangOptions &LangOpts, llvm::function_ref< void(const clang::Token &, const SourceManager &SM)> Action)
Represents locations that can accept a definition.
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
llvm::Optional< FileDigest > digestFile(const SourceManager &SM, FileID FID)
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, llvm::vfs::FileSystem *FS)
Choose the clang-format style we should apply to a certain file.
static SourceLocation getLocForTokenBegin(SourceLocation EndLoc, const SourceManager &SM, const LangOptions &LangOpts)
tooling::Replacements Replacements
FileDigest digest(llvm::StringRef Content)
llvm::Optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
SourceLocation includeHashLoc(FileID IncludedFile, const SourceManager &SM)
Returns the #include location through which IncludedFIle was loaded.
int line
Line position in a document (zero-based).
llvm::StringRef toSourceCode(const SourceManager &SM, SourceRange R)
Returns the source code covered by the source range.
int character
Character offset on a line in a document (zero-based).
static SourceRange getTokenFileRange(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
TextEdit replacementToEdit(llvm::StringRef Code, const tooling::Replacement &R)
llvm::Optional< std::string > getCanonicalPath(const FileEntry *F, const SourceManager &SourceMgr)
Get the canonical path of F.
static SourceLocation getLocForTokenEnd(SourceLocation BeginLoc, const SourceManager &SM, const LangOptions &LangOpts)
std::vector< TextEdit > replacementsToEdits(llvm::StringRef Code, const tooling::Replacements &Repls)
std::vector< TextEdit > asTextEdits() const
Represents Replacements as TextEdits that are available for use in LSP.
bool isHeaderFile(llvm::StringRef FileName, llvm::Optional< LangOptions > LangOpts)
Infers whether this is a header from the FileName and LangOpts (if presents).
llvm::Optional< FixItHint > FixIt
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
Position end
The range's end position.
static OffsetEncoding lspEncoding()
std::vector< Range > collectIdentifierRanges(llvm::StringRef Identifier, llvm::StringRef Content, const LangOptions &LangOpts)
Collects all ranges of the given identifier in the source code.
llvm::StringMap< unsigned > collectIdentifiers(llvm::StringRef Content, const format::FormatStyle &Style)
Collects identifiers with counts in the source code.
llvm::Optional< DefinedMacro > locateMacroAt(SourceLocation Loc, Preprocessor &PP)
Gets the macro at a specified Loc.
static bool iterateCodepoints(llvm::StringRef U8, const Callback &CB)
A set of edits generated for a single file.
static unsigned getTokenLengthAtLoc(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
llvm::Error reformatEdit(Edit &E, const format::FormatStyle &Style)
Formats the edits and code around it according to Style.
std::vector< Position > EligiblePoints
Offsets into the code marking eligible points to insert a function definition.
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
static cl::opt< std::string > FormatStyle("format-style", cl::desc(R"(
Style for formatting code around applied fixes:
- 'none' (default) turns off formatting
- 'file' (literally 'file', not a placeholder)
uses .clang-format file in the closest parent
directory
- '{ <json> }' specifies options inline, e.g.
-format-style='{BasedOnStyle: llvm, IndentWidth: 8}'
- 'llvm', 'google', 'webkit', 'mozilla'
See clang-format documentation for the up-to-date
information about formatting styles and options.
This option overrides the 'FormatStyle` option in
.clang-tidy file, if any.
)"), cl::init("none"), cl::cat(ClangTidyCategory))