summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clangd/CodeComplete.cpp7
-rw-r--r--clang-tools-extra/clangd/CodeCompletionStrings.cpp22
-rw-r--r--clang-tools-extra/clangd/CodeCompletionStrings.h11
-rw-r--r--clang-tools-extra/clangd/index/SymbolCollector.cpp3
-rw-r--r--clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp41
5 files changed, 75 insertions, 9 deletions
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index da3d238c8ad..4adb80c8470 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -586,9 +586,11 @@ public:
const auto *CCS = Candidate.CreateSignatureString(
CurrentArg, S, *Allocator, CCTUInfo, true);
assert(CCS && "Expected the CodeCompletionString to be non-null");
+ // FIXME: for headers, we need to get a comment from the index.
SigHelp.signatures.push_back(ProcessOverloadCandidate(
Candidate, *CCS,
- getParameterDocComment(S.getASTContext(), Candidate, CurrentArg)));
+ getParameterDocComment(S.getASTContext(), Candidate, CurrentArg,
+ /*CommentsFromHeader=*/false)));
}
}
@@ -1030,7 +1032,8 @@ private:
SemaCCS = Recorder->codeCompletionString(*SR);
if (Opts.IncludeComments) {
assert(Recorder->CCSema);
- DocComment = getDocComment(Recorder->CCSema->getASTContext(), *SR);
+ DocComment = getDocComment(Recorder->CCSema->getASTContext(), *SR,
+ /*CommentsFromHeader=*/false);
}
}
return Candidate.build(FileName, Scores, Opts, SemaCCS, Includes.get(), DocComment);
diff --git a/clang-tools-extra/clangd/CodeCompletionStrings.cpp b/clang-tools-extra/clangd/CodeCompletionStrings.cpp
index cbdd14d1095..f918a54c41c 100644
--- a/clang-tools-extra/clangd/CodeCompletionStrings.cpp
+++ b/clang-tools-extra/clangd/CodeCompletionStrings.cpp
@@ -10,6 +10,7 @@
#include "CodeCompletionStrings.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RawCommentList.h"
+#include "clang/Basic/SourceManager.h"
#include <utility>
namespace clang {
@@ -122,10 +123,23 @@ void processSnippetChunks(const CodeCompletionString &CCS,
}
}
+std::string getFormattedComment(const ASTContext &Ctx, const RawComment &RC,
+ bool CommentsFromHeaders) {
+ auto &SourceMgr = Ctx.getSourceManager();
+ // Parsing comments from invalid preamble can lead to crashes. So we only
+ // return comments from the main file when doing code completion. For
+ // indexing, we still read all the comments.
+ // FIXME: find a better fix, e.g. store file contents in the preamble or get
+ // doc comments from the index.
+ if (!CommentsFromHeaders && !SourceMgr.isWrittenInMainFile(RC.getLocStart()))
+ return "";
+ return RC.getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
+}
} // namespace
std::string getDocComment(const ASTContext &Ctx,
- const CodeCompletionResult &Result) {
+ const CodeCompletionResult &Result,
+ bool CommentsFromHeaders) {
// FIXME: clang's completion also returns documentation for RK_Pattern if they
// contain a pattern for ObjC properties. Unfortunately, there is no API to
// get this declaration, so we don't show documentation in that case.
@@ -137,20 +151,20 @@ std::string getDocComment(const ASTContext &Ctx,
const RawComment *RC = getCompletionComment(Ctx, Decl);
if (!RC)
return "";
- return RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
+ return getFormattedComment(Ctx, *RC, CommentsFromHeaders);
}
std::string
getParameterDocComment(const ASTContext &Ctx,
const CodeCompleteConsumer::OverloadCandidate &Result,
- unsigned ArgIndex) {
+ unsigned ArgIndex, bool CommentsFromHeaders) {
auto Func = Result.getFunction();
if (!Func)
return "";
const RawComment *RC = getParameterComment(Ctx, Result, ArgIndex);
if (!RC)
return "";
- return RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
+ return getFormattedComment(Ctx, *RC, CommentsFromHeaders);
}
void getLabelAndInsertText(const CodeCompletionString &CCS, std::string *Label,
diff --git a/clang-tools-extra/clangd/CodeCompletionStrings.h b/clang-tools-extra/clangd/CodeCompletionStrings.h
index c29350d15e7..81d184cfba8 100644
--- a/clang-tools-extra/clangd/CodeCompletionStrings.h
+++ b/clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -25,18 +25,25 @@ namespace clangd {
/// markers stripped. See clang::RawComment::getFormattedText() for the detailed
/// explanation of how the comment text is transformed.
/// Returns empty string when no comment is available.
+/// If \p CommentsFromHeaders parameter is set, only comments from the main
+/// file will be returned. It is used to workaround crashes when parsing
+/// comments in the stale headers, coming from completion preamble.
std::string getDocComment(const ASTContext &Ctx,
- const CodeCompletionResult &Result);
+ const CodeCompletionResult &Result,
+ bool CommentsFromHeaders);
/// Gets a minimally formatted documentation for parameter of \p Result,
/// corresponding to argument number \p ArgIndex.
/// This currently looks for comments attached to the parameter itself, and
/// doesn't extract them from function documentation.
/// Returns empty string when no comment is available.
+/// If \p CommentsFromHeaders parameter is set, only comments from the main
+/// file will be returned. It is used to workaround crashes when parsing
+/// comments in the stale headers, coming from completion preamble.
std::string
getParameterDocComment(const ASTContext &Ctx,
const CodeCompleteConsumer::OverloadCandidate &Result,
- unsigned ArgIndex);
+ unsigned ArgIndex, bool CommentsFromHeaders);
/// Gets label and insert text for a completion item. For example, for function
/// `Foo`, this returns <"Foo(int x, int y)", "Foo"> without snippts enabled.
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index 1d90a5e61a6..482a4652fae 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -389,7 +389,8 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND,
/*EnableSnippets=*/false);
std::string FilterText = getFilterText(*CCS);
std::string Documentation =
- formatDocumentation(*CCS, getDocComment(Ctx, SymbolCompletion));
+ formatDocumentation(*CCS, getDocComment(Ctx, SymbolCompletion,
+ /*CommentsFromHeaders=*/true));
std::string CompletionDetail = getDetail(*CCS);
std::string Include;
diff --git a/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp b/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp
index 4133f946ff5..afa6f1b8d91 100644
--- a/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp
+++ b/clang-tools-extra/unittests/clangd/CodeCompleteTests.cpp
@@ -17,6 +17,7 @@
#include "SyncAPI.h"
#include "TestFS.h"
#include "index/MemIndex.h"
+#include "llvm/Support/Error.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -998,6 +999,46 @@ TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
}
}
+TEST(CompletionTest, DocumentationFromChangedFileCrash) {
+ MockFSProvider FS;
+ auto FooH = testPath("foo.h");
+ auto FooCpp = testPath("foo.cpp");
+ FS.Files[FooH] = R"cpp(
+ // this is my documentation comment.
+ int func();
+ )cpp";
+ FS.Files[FooCpp] = "";
+
+ MockCompilationDatabase CDB;
+ IgnoreDiagnostics DiagConsumer;
+ ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+ Annotations Source(R"cpp(
+ #include "foo.h"
+ int func() {
+ // This makes sure we have func from header in the AST.
+ }
+ int a = fun^
+ )cpp");
+ Server.addDocument(FooCpp, Source.code(), WantDiagnostics::Yes);
+ // We need to wait for preamble to build.
+ ASSERT_TRUE(Server.blockUntilIdleForTest());
+
+ // Change the header file. Completion will reuse the old preamble!
+ FS.Files[FooH] = R"cpp(
+ int func();
+ )cpp";
+
+ clangd::CodeCompleteOptions Opts;
+ Opts.IncludeComments = true;
+ CompletionList Completions =
+ cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));
+ // We shouldn't crash. Unfortunately, current workaround is to not produce
+ // comments for symbols from headers.
+ EXPECT_THAT(Completions.items,
+ Contains(AllOf(Not(IsDocumented()), Named("func"))));
+}
+
} // namespace
} // namespace clangd
} // namespace clang
OpenPOWER on IntegriCloud