summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Donchevskii <ivan.donchevskii@qt.io>2018-05-17 11:50:03 +0200
committerIvan Donchevskii <ivan.donchevskii@qt.io>2018-06-14 06:14:52 +0000
commite775457c4ede090c31de56fe20e5c59b6fe46b95 (patch)
treebb0158197bc7651e87b1beabbd6ea942d41bc992
parent74dff2b4165421e67427db09f02d6a52ae1fa96d (diff)
[backported/clang-7][libclang] Optionally add code completion results for arrow instead of dot
-------------------------------------------------------------------------- * https://reviews.llvm.org/D46862 -------------------------------------------------------------------------- Follow up for https://reviews.llvm.org/D41537 - libclang part is extracted into this review Change-Id: Ib166eb7b8675be605c81330df0c5f342942815ce Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
-rw-r--r--include/clang-c/Index.h87
-rw-r--r--include/clang/Basic/SourceManager.h12
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h50
-rw-r--r--test/Index/complete-arrow-dot.cpp54
-rw-r--r--tools/c-index-test/c-index-test.c46
-rw-r--r--tools/libclang/CIndex.cpp36
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp57
-rw-r--r--tools/libclang/libclang.exports3
8 files changed, 313 insertions, 32 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index d06c82a4db..41534f68e6 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -36,6 +36,7 @@
#define CINDEX_VERSION_HAS_ISINVALIDECL_BACKPORTED
#define CINDEX_VERSION_HAS_PRETTYDECL_BACKPORTED
#define CINDEX_VERSION_HAS_LIMITSKIPFUNCTIONBODIESTOPREAMBLE_BACKPORTED
+#define CINDEX_VERSION_HAS_COMPLETION_FIXITS_BACKPORTED
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -4738,6 +4739,20 @@ typedef struct {
} CXToken;
/**
+ * \brief Get the raw lexical token starting with the given location.
+ *
+ * \param TU the translation unit whose text is being tokenized.
+ *
+ * \param Location the source location with which the token starts.
+ *
+ * \returns The token starting with the given location or NULL if no such tokens
+ * exist. The returned pointer must be freed with clang_disposeTokens before the
+ * translation unit is destroyed.
+ */
+CINDEX_LINKAGE CXToken *clang_getToken(CXTranslationUnit TU,
+ CXSourceLocation Location);
+
+/**
* \brief Determine the kind of the given token.
*/
CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken);
@@ -5233,6 +5248,70 @@ typedef struct {
} CXCodeCompleteResults;
/**
+ * \brief Retrieve the number of fix-its for the given completion string.
+ *
+ * Calling this makes sense only if CXCodeComplete_IncludeCompletionsWithFixIts
+ * option was set.
+ *
+ * \param results The structure keeping all completion results
+ *
+ * \param completion_index The index of the completion
+ *
+ * \return The number of fix-its which must be applied before the completion at
+ * completion_index can be applied
+ */
+CINDEX_LINKAGE unsigned
+clang_getCompletionNumFixIts(CXCodeCompleteResults *results,
+ unsigned completion_index);
+
+/**
+ * \brief Fix-its that *must* be applied before inserting the text for the
+ * corresponding completion.
+ *
+ * By default, clang_codeCompleteAt() only returns completions with empty
+ * fix-its. Extra completions with non-empty fix-its should be explicitly
+ * requested by setting CXCodeComplete_IncludeCompletionsWithFixIts.
+ *
+ * For the clients to be able to compute position of the cursor after applying
+ * fix-its, the following conditions are guaranteed to hold for
+ * replacement_range of the stored fix-its:
+ * - Ranges in the fix-its are guaranteed to never contain the completion
+ * point (or identifier under completion point, if any) inside them, except
+ * at the start or at the end of the range.
+ * - If a fix-it range starts or ends with completion point (or starts or
+ * ends after the identifier under completion point), it will contain at
+ * least one character. It allows to unambiguously recompute completion
+ * point after applying the fix-it.
+ *
+ * The intuition is that provided fix-its change code around the identifier we
+ * complete, but are not allowed to touch the identifier itself or the
+ * completion point. One example of completions with corrections are the ones
+ * replacing '.' with '->' and vice versa:
+ *
+ * std::unique_ptr<std::vector<int>> vec_ptr;
+ * In 'vec_ptr.^', one of the completions is 'push_back', it requires
+ * replacing '.' with '->'.
+ * In 'vec_ptr->^', one of the completions is 'release', it requires
+ * replacing '->' with '.'.
+ *
+ * \param results The structure keeping all completion results
+ *
+ * \param completion_index The index of the completion
+ *
+ * \param fixit_index The index of the fix-it for the completion at
+ * completion_index
+ *
+ * \param replacement_range The fix-it range that must be replaced before the
+ * completion at completion_index can be applied
+ *
+ * \returns The fix-it string that must replace the code at replacement_range
+ * before the completion at completion_index can be applied
+ */
+CINDEX_LINKAGE CXString clang_getCompletionFixIt(
+ CXCodeCompleteResults *results, unsigned completion_index,
+ unsigned fixit_index, CXSourceRange *replacement_range);
+
+/**
* \brief Flags that can be passed to \c clang_codeCompleteAt() to
* modify its behavior.
*
@@ -5256,7 +5335,13 @@ enum CXCodeComplete_Flags {
* \brief Whether to include brief documentation within the set of code
* completions returned.
*/
- CXCodeComplete_IncludeBriefComments = 0x04
+ CXCodeComplete_IncludeBriefComments = 0x04,
+
+ /**
+ * \brief Whether to include completions with small
+ * fix-its, e.g. change '.' to '->' on member access, etc.
+ */
+ CXCodeComplete_IncludeCompletionsWithFixIts = 0x10
};
/**
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 397ad2e77f..80e277384c 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -1137,6 +1137,18 @@ public:
/// be used by clients.
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const;
+ /// Form a SourceLocation from a FileID and Offset pair.
+ SourceLocation getComposedLoc(FileID FID, unsigned Offset) const {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid)
+ return SourceLocation();
+
+ unsigned GlobalOffset = Entry.getOffset() + Offset;
+ return Entry.isFile() ? SourceLocation::getFileLoc(GlobalOffset)
+ : SourceLocation::getMacroLoc(GlobalOffset);
+ }
+
/// \brief Decompose the specified location into a raw FileID + Offset pair.
///
/// The first element is the FileID, the second is the offset from the
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index 720a150f51..002f93ade2 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -680,30 +680,33 @@ public:
/// \brief The availability of this result.
CXAvailabilityKind Availability;
- /// \brief FixIts that *must* be applied before inserting the text for the
- /// corresponding completion item.
+ ///\brief Fix-its that *must* be applied before inserting the text for the
+ /// corresponding completion.
///
- /// Completion items with non-empty fixits will not be returned by default,
- /// they should be explicitly requested by setting
- /// CompletionOptions::IncludeFixIts. For the editors to be able to
- /// compute position of the cursor for the completion item itself, the
- /// following conditions are guaranteed to hold for RemoveRange of the stored
- /// fixits:
- /// - Ranges in the fixits are guaranteed to never contain the completion
+ /// By default, CodeCompletionBuilder only returns completions with empty
+ /// fix-its. Extra completions with non-empty fix-its should be explicitly
+ /// requested by setting CompletionOptions::IncludeFixIts.
+ ///
+ /// For the clients to be able to compute position of the cursor after
+ /// applying fix-its, the following conditions are guaranteed to hold for
+ /// RemoveRange of the stored fix-its:
+ /// - Ranges in the fix-its are guaranteed to never contain the completion
/// point (or identifier under completion point, if any) inside them, except
/// at the start or at the end of the range.
- /// - If a fixit range starts or ends with completion point (or starts or
+ /// - If a fix-it range starts or ends with completion point (or starts or
/// ends after the identifier under completion point), it will contain at
/// least one character. It allows to unambiguously recompute completion
- /// point after applying the fixit.
- /// The intuition is that provided fixits change code around the identifier we
- /// complete, but are not allowed to touch the identifier itself or the
- /// completion point. One example of completion items with corrections are the
- /// ones replacing '.' with '->' and vice versa:
+ /// point after applying the fix-it.
+ ///
+ /// The intuition is that provided fix-its change code around the identifier
+ /// we complete, but are not allowed to touch the identifier itself or the
+ /// completion point. One example of completions with corrections are the ones
+ /// replacing '.' with '->' and vice versa:
+ ///
/// std::unique_ptr<std::vector<int>> vec_ptr;
- /// In 'vec_ptr.^', one of completion items is 'push_back', it requires
+ /// In 'vec_ptr.^', one of the completions is 'push_back', it requires
/// replacing '.' with '->'.
- /// In 'vec_ptr->^', one of completion items is 'release', it requires
+ /// In 'vec_ptr->^', one of the completions is 'release', it requires
/// replacing '->' with '.'.
std::vector<FixItHint> FixIts;
@@ -736,13 +739,12 @@ public:
bool QualifierIsInformative = false,
bool Accessible = true,
std::vector<FixItHint> FixIts = std::vector<FixItHint>())
- : Declaration(Declaration), Priority(Priority),
- StartParameter(0), Kind(RK_Declaration),
- Availability(CXAvailability_Available), Hidden(false),
- QualifierIsInformative(QualifierIsInformative),
- StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
- DeclaringEntity(false), Qualifier(Qualifier),
- FixIts(std::move(FixIts)) {
+ : Declaration(Declaration), Priority(Priority), StartParameter(0),
+ Kind(RK_Declaration), Availability(CXAvailability_Available),
+ FixIts(std::move(FixIts)), Hidden(false),
+ QualifierIsInformative(QualifierIsInformative),
+ StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
+ DeclaringEntity(false), Qualifier(Qualifier) {
//FIXME: Add assert to check FixIts range requirements.
computeCursorKindAndAvailability(Accessible);
}
diff --git a/test/Index/complete-arrow-dot.cpp b/test/Index/complete-arrow-dot.cpp
new file mode 100644
index 0000000000..fb5efbe6e6
--- /dev/null
+++ b/test/Index/complete-arrow-dot.cpp
@@ -0,0 +1,54 @@
+struct X {
+ void doSomething();
+
+ int field;
+};
+
+void X::doSomething() {
+ // RUN: c-index-test -code-completion-at=%s:10:8 %s | FileCheck %s
+ // RUN: env CINDEXTEST_COMPLETION_INCLUDE_FIXITS=1 c-index-test -code-completion-at=%s:10:8 %s | FileCheck -check-prefix=CHECK-WITH-CORRECTION %s
+ this.;
+}
+
+void doSomething() {
+ // RUN: c-index-test -code-completion-at=%s:17:6 %s | FileCheck -check-prefix=CHECK-ARROW-TO-DOT %s
+ // RUN: env CINDEXTEST_COMPLETION_INCLUDE_FIXITS=1 c-index-test -code-completion-at=%s:17:6 %s | FileCheck -check-prefix=CHECK-ARROW-TO-DOT-WITH-CORRECTION %s
+ X x;
+ x->
+}
+
+// CHECK-NOT: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34) (requires fix-it:{{.*}}
+// CHECK-NOT: FieldDecl:{ResultType int}{TypedText field} (35) (requires fix-it:{{.*}}
+// CHECK-NOT: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-NOT: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder X &&}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-NOT: StructDecl:{TypedText X}{Text ::} (75) (requires fix-it:{{.*}}
+// CHECK-NOT: CXXDestructor:{ResultType void}{TypedText ~X}{LeftParen (}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK: Completion contexts:
+// CHECK-NEXT: Dot member access
+
+// CHECK-WITH-CORRECTION: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34) (requires fix-it:{{.*}}
+// CHECK-WITH-CORRECTION-NEXT: FieldDecl:{ResultType int}{TypedText field} (35) (requires fix-it:{{.*}}
+// CHECK-WITH-CORRECTION-NEXT: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-WITH-CORRECTION-NEXT: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder X &&}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-WITH-CORRECTION-NEXT: StructDecl:{TypedText X}{Text ::} (75) (requires fix-it:{{.*}}
+// CHECK-WITH-CORRECTION-NEXT: CXXDestructor:{ResultType void}{TypedText ~X}{LeftParen (}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-WITH-CORRECTION-NEXT: Completion contexts:
+// CHECK-WITH-CORRECTION-NEXT: Dot member access
+
+// CHECK-ARROW-TO-DOT-NOT: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-NOT: FieldDecl:{ResultType int}{TypedText field} (35) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-NOT: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-NOT: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder X &&}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-NOT: StructDecl:{TypedText X}{Text ::} (75) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-NOT: CXXDestructor:{ResultType void}{TypedText ~X}{LeftParen (}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT: Completion contexts:
+// CHECK-ARROW-TO-DOT-NEXT: Unknown
+
+// CHECK-ARROW-TO-DOT-WITH-CORRECTION: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-WITH-CORRECTION-NEXT: FieldDecl:{ResultType int}{TypedText field} (35) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-WITH-CORRECTION-NEXT: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-WITH-CORRECTION-NEXT: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder X &&}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-WITH-CORRECTION-NEXT: StructDecl:{TypedText X}{Text ::} (75) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-WITH-CORRECTION-NEXT: CXXDestructor:{ResultType void}{TypedText ~X}{LeftParen (}{RightParen )} (79) (requires fix-it:{{.*}}
+// CHECK-ARROW-TO-DOT-WITH-CORRECTION-NEXT: Completion contexts:
+// CHECK-ARROW-TO-DOT-WITH-CORRECTION-NEXT: Arrow member access
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index bcc42ad994..45348a21c4 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -2254,8 +2254,33 @@ static void print_completion_string(CXCompletionString completion_string,
}
-static void print_completion_result(CXCompletionResult *completion_result,
+static void print_line_column(CXSourceLocation location, FILE *file) {
+ unsigned line, column;
+ clang_getExpansionLocation(location, NULL, &line, &column, NULL);
+ fprintf(file, "%d:%d", line, column);
+}
+
+static void print_token_range(CXTranslationUnit translation_unit,
+ CXSourceLocation start, FILE *file) {
+ CXToken *token = clang_getToken(translation_unit, start);
+
+ fprintf(file, "{");
+ if (token != NULL) {
+ CXSourceRange token_range = clang_getTokenExtent(translation_unit, *token);
+ print_line_column(clang_getRangeStart(token_range), file);
+ fprintf(file, "-");
+ print_line_column(clang_getRangeEnd(token_range), file);
+ clang_disposeTokens(translation_unit, token, 1);
+ }
+
+ fprintf(file, "}");
+}
+
+static void print_completion_result(CXTranslationUnit translation_unit,
+ CXCodeCompleteResults *completion_results,
+ unsigned index,
FILE *file) {
+ CXCompletionResult *completion_result = completion_results->Results + index;
CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
unsigned annotationCount;
enum CXCursorKind ParentKind;
@@ -2263,6 +2288,7 @@ static void print_completion_result(CXCompletionResult *completion_result,
CXString BriefComment;
CXString Annotation;
const char *BriefCommentCString;
+ unsigned i;
fprintf(file, "%s:", clang_getCString(ks));
clang_disposeString(ks);
@@ -2323,7 +2349,19 @@ static void print_completion_result(CXCompletionResult *completion_result,
fprintf(file, "(brief comment: %s)", BriefCommentCString);
}
clang_disposeString(BriefComment);
-
+
+ for (i = 0; i < clang_getCompletionNumFixIts(completion_results, index);
+ ++i) {
+ CXSourceRange correction_range;
+ CXString FixIt = clang_getCompletionFixIt(completion_results, index, i,
+ &correction_range);
+ fprintf(file, " (requires fix-it: ");
+ print_token_range(translation_unit, clang_getRangeStart(correction_range),
+ file);
+ fprintf(file, " to \"%s\")", clang_getCString(FixIt));
+ clang_disposeString(FixIt);
+ }
+
fprintf(file, "\n");
}
@@ -2420,6 +2458,8 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
completionOptions |= CXCodeComplete_IncludeCodePatterns;
if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
completionOptions |= CXCodeComplete_IncludeBriefComments;
+ if (getenv("CINDEXTEST_COMPLETION_INCLUDE_FIXITS"))
+ completionOptions |= CXCodeComplete_IncludeCompletionsWithFixIts;
if (timing_only)
input += strlen("-code-completion-timing=");
@@ -2484,7 +2524,7 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
clang_sortCodeCompletionResults(results->Results, results->NumResults);
for (i = 0; i != n; ++i)
- print_completion_result(results->Results + i, stdout);
+ print_completion_result(TU, results, i, stdout);
}
n = clang_codeCompleteGetNumDiagnostics(results);
for (i = 0; i != n; ++i) {
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 884206d9d1..c44c72e2ed 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -6642,6 +6642,42 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
} while (Lex.getBufferLocation() < EffectiveBufferEnd);
}
+CXToken *clang_getToken(CXTranslationUnit TU, CXSourceLocation Location) {
+ LOG_FUNC_SECTION {
+ *Log << TU << ' ' << Location;
+ }
+
+ if (isNotUsableTU(TU)) {
+ LOG_BAD_TU(TU);
+ return nullptr;
+ }
+
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
+ if (!CXXUnit)
+ return nullptr;
+
+ SourceLocation Begin = cxloc::translateSourceLocation(Location);
+ if (Begin.isInvalid())
+ return nullptr;
+ SourceManager &SM = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> DecomposedEnd = SM.getDecomposedLoc(Begin);
+ DecomposedEnd.second += Lexer::MeasureTokenLength(Begin, SM, CXXUnit->getLangOpts());
+
+ SourceLocation End = SM.getComposedLoc(DecomposedEnd.first, DecomposedEnd.second);
+
+ SmallVector<CXToken, 32> CXTokens;
+ getTokens(CXXUnit, SourceRange(Begin, End), CXTokens);
+
+ if (CXTokens.empty())
+ return nullptr;
+
+ CXTokens.resize(1);
+ CXToken *Token = (CXToken *)malloc(sizeof(CXToken));
+
+ memmove(Token, CXTokens.data(), sizeof(CXToken));
+ return Token;
+}
+
void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
CXToken **Tokens, unsigned *NumTokens) {
LOG_FUNC_SECTION {
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index d4af0870c0..32fc7325f0 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -16,6 +16,7 @@
#include "CIndexDiagnostic.h"
#include "CLog.h"
#include "CXCursor.h"
+#include "CXSourceLocation.h"
#include "CXString.h"
#include "CXTranslationUnit.h"
#include "clang/AST/Decl.h"
@@ -302,10 +303,53 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief A string containing the Objective-C selector entered thus far for a
/// message send.
std::string Selector;
+
+ /// \brief Vector of fix-its for each completion result that *must* be applied
+ /// before that result for the corresponding completion item.
+ std::vector<std::vector<FixItHint>> FixItsVector;
};
} // end anonymous namespace
+unsigned clang_getCompletionNumFixIts(CXCodeCompleteResults *results,
+ unsigned completion_index) {
+ AllocatedCXCodeCompleteResults *allocated_results = (AllocatedCXCodeCompleteResults *)results;
+
+ if (!allocated_results || allocated_results->FixItsVector.size() <= completion_index)
+ return 0;
+
+ return static_cast<unsigned>(allocated_results->FixItsVector[completion_index].size());
+}
+
+CXString clang_getCompletionFixIt(CXCodeCompleteResults *results,
+ unsigned completion_index,
+ unsigned fixit_index,
+ CXSourceRange *replacement_range) {
+ AllocatedCXCodeCompleteResults *allocated_results = (AllocatedCXCodeCompleteResults *)results;
+
+ if (!allocated_results || allocated_results->FixItsVector.size() <= completion_index) {
+ if (replacement_range)
+ *replacement_range = clang_getNullRange();
+ return cxstring::createNull();
+ }
+
+ ArrayRef<FixItHint> FixIts = allocated_results->FixItsVector[completion_index];
+ if (FixIts.size() <= fixit_index) {
+ if (replacement_range)
+ *replacement_range = clang_getNullRange();
+ return cxstring::createNull();
+ }
+
+ const FixItHint &FixIt = FixIts[fixit_index];
+ if (replacement_range) {
+ *replacement_range = cxloc::translateSourceRange(
+ *allocated_results->SourceMgr, allocated_results->LangOpts,
+ FixIt.RemoveRange);
+ }
+
+ return cxstring::createRef(FixIt.CodeToInsert.c_str());
+}
+
/// \brief Tracks the number of code-completion result objects that are
/// currently active.
///
@@ -531,8 +575,10 @@ namespace {
CodeCompletionResult *Results,
unsigned NumResults) override {
StoredResults.reserve(StoredResults.size() + NumResults);
+ if (includeFixIts())
+ AllocatedResults.FixItsVector.reserve(NumResults);
for (unsigned I = 0; I != NumResults; ++I) {
- CodeCompletionString *StoredCompletion
+ CodeCompletionString *StoredCompletion
= Results[I].CreateCodeCompletionString(S, Context, getAllocator(),
getCodeCompletionTUInfo(),
includeBriefComments());
@@ -541,8 +587,10 @@ namespace {
R.CursorKind = Results[I].CursorKind;
R.CompletionString = StoredCompletion;
StoredResults.push_back(R);
+ if (includeFixIts())
+ AllocatedResults.FixItsVector.emplace_back(std::move(Results[I].FixIts));
}
-
+
enum CodeCompletionContext::Kind contextKind = Context.getKind();
AllocatedResults.ContextKind = contextKind;
@@ -643,13 +691,13 @@ clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename,
ArrayRef<CXUnsavedFile> unsaved_files,
unsigned options) {
bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments;
+ bool IncludeFixIts = options & CXCodeComplete_IncludeCompletionsWithFixIts;
#ifdef UDP_CODE_COMPLETION_LOGGER
#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
#endif
#endif
-
bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != nullptr;
if (cxtu::isNotUsableTU(TU)) {
@@ -689,6 +737,7 @@ clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename,
// Create a code-completion consumer to capture the results.
CodeCompleteOptions Opts;
Opts.IncludeBriefComments = IncludeBriefComments;
+ Opts.IncludeFixIts = IncludeFixIts;
CaptureCompletionResults Capture(Opts, *Results, &TU);
// Perform completion.
@@ -962,7 +1011,7 @@ namespace {
= (CodeCompletionString *)XR.CompletionString;
CodeCompletionString *Y
= (CodeCompletionString *)YR.CompletionString;
-
+
SmallString<256> XBuffer;
StringRef XText = GetTypedName(X, XBuffer);
SmallString<256> YBuffer;
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 67e4b4334b..8deca1cb50 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -170,6 +170,8 @@ clang_getCompletionBriefComment
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
+clang_getCompletionNumFixIts
+clang_getCompletionFixIt
clang_getCompletionNumAnnotations
clang_getCompletionParent
clang_getCompletionPriority
@@ -259,6 +261,7 @@ clang_getSpecializedCursorTemplate
clang_getSpellingLocation
clang_getTUResourceUsageName
clang_getTemplateCursorKind
+clang_getToken
clang_getTokenExtent
clang_getTokenKind
clang_getTokenLocation