diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1373,8 +1373,9 @@ // - accessible scopes are determined heuristically. // - all-scopes query if no qualifier was typed (and it's allowed). SpecifiedScope Scopes; + LangOptions LangOpts = format::getFormattingLangOpts(Style); Scopes.AccessibleScopes = - visibleNamespaces(Content.take_front(Offset), Style); + visibleNamespaces(Content.take_front(Offset), LangOpts); for (std::string &S : Scopes.AccessibleScopes) if (!S.empty()) S.append("::"); // visibleNamespaces doesn't include trailing ::. @@ -1772,8 +1773,7 @@ Options.IncludeBriefComments = false; IncludeStructure PreambleInclusions; // Unused for signatureHelp semaCodeComplete( - std::make_unique(Options, Index, Result), - Options, + std::make_unique(Options, Index, Result), Options, {FileName, Command, Preamble, Contents, *Offset, std::move(VFS)}); return Result; } diff --git a/clang-tools-extra/clangd/SourceCode.h b/clang-tools-extra/clangd/SourceCode.h --- a/clang-tools-extra/clangd/SourceCode.h +++ b/clang-tools-extra/clangd/SourceCode.h @@ -250,7 +250,7 @@ /// /// visibleNamespaces are {"foo::", "", "a::", "b::", "foo::b::"}, not "a::b::". std::vector visibleNamespaces(llvm::StringRef Code, - const format::FormatStyle &Style); + const LangOptions &LangOpts); /// Represents locations that can accept a definition. struct EligibleRegion { @@ -271,7 +271,7 @@ /// \p FullyQualifiedName should not contain anonymous namespaces. EligibleRegion getEligiblePoints(llvm::StringRef Code, llvm::StringRef FullyQualifiedName, - const format::FormatStyle &Style); + const LangOptions &LangOpts); struct DefinedMacro { llvm::StringRef Name; diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -651,8 +651,7 @@ Position Pos; }; // Scans C++ source code for constructs that change the visible namespaces. -void parseNamespaceEvents(llvm::StringRef Code, - const format::FormatStyle &Style, +void parseNamespaceEvents(llvm::StringRef Code, const LangOptions &LangOpts, llvm::function_ref Callback) { // Stack of enclosing namespaces, e.g. {"clang", "clangd"} @@ -671,114 +670,113 @@ std::string NSName; NamespaceEvent Event; - lex(Code, format::getFormattingLangOpts(Style), - [&](const syntax::Token &Tok, const SourceManager &SM) { - Event.Pos = sourceLocToPosition(SM, Tok.location()); - switch (Tok.kind()) { - case tok::kw_using: - State = State == Default ? Using : Default; - break; - case tok::kw_namespace: - switch (State) { - case Using: - State = UsingNamespace; - break; - case Default: - State = Namespace; - break; - default: - State = Default; - break; - } - break; - case tok::identifier: - switch (State) { - case UsingNamespace: - NSName.clear(); - LLVM_FALLTHROUGH; - case UsingNamespaceName: - NSName.append(Tok.text(SM).str()); - State = UsingNamespaceName; - break; - case Namespace: - NSName.clear(); - LLVM_FALLTHROUGH; - case NamespaceName: - NSName.append(Tok.text(SM).str()); - State = NamespaceName; - break; - case Using: - case Default: - State = Default; - break; - } - break; - case tok::coloncolon: - // This can come at the beginning or in the middle of a namespace - // name. - switch (State) { - case UsingNamespace: - NSName.clear(); - LLVM_FALLTHROUGH; - case UsingNamespaceName: - NSName.append("::"); - State = UsingNamespaceName; - break; - case NamespaceName: - NSName.append("::"); - State = NamespaceName; - break; - case Namespace: // Not legal here. - case Using: - case Default: - State = Default; - break; - } - break; - case tok::l_brace: - // Record which { started a namespace, so we know when } ends one. - if (State == NamespaceName) { - // Parsed: namespace { - BraceStack.push_back(true); - Enclosing.push_back(NSName); - Event.Trigger = NamespaceEvent::BeginNamespace; - Event.Payload = llvm::join(Enclosing, "::"); - Callback(Event); - } else { - // This case includes anonymous namespaces (State = Namespace). - // For our purposes, they're not namespaces and we ignore them. - BraceStack.push_back(false); - } - State = Default; - break; - case tok::r_brace: - // If braces are unmatched, we're going to be confused, but don't - // crash. - if (!BraceStack.empty()) { - if (BraceStack.back()) { - // Parsed: } // namespace - Enclosing.pop_back(); - Event.Trigger = NamespaceEvent::EndNamespace; - Event.Payload = llvm::join(Enclosing, "::"); - Callback(Event); - } - BraceStack.pop_back(); - } - break; - case tok::semi: - if (State == UsingNamespaceName) { - // Parsed: using namespace ; - Event.Trigger = NamespaceEvent::UsingDirective; - Event.Payload = std::move(NSName); - Callback(Event); - } - State = Default; - break; - default: - State = Default; - break; + lex(Code, LangOpts, [&](const syntax::Token &Tok, const SourceManager &SM) { + Event.Pos = sourceLocToPosition(SM, Tok.location()); + switch (Tok.kind()) { + case tok::kw_using: + State = State == Default ? Using : Default; + break; + case tok::kw_namespace: + switch (State) { + case Using: + State = UsingNamespace; + break; + case Default: + State = Namespace; + break; + default: + State = Default; + break; + } + break; + case tok::identifier: + switch (State) { + case UsingNamespace: + NSName.clear(); + LLVM_FALLTHROUGH; + case UsingNamespaceName: + NSName.append(Tok.text(SM).str()); + State = UsingNamespaceName; + break; + case Namespace: + NSName.clear(); + LLVM_FALLTHROUGH; + case NamespaceName: + NSName.append(Tok.text(SM).str()); + State = NamespaceName; + break; + case Using: + case Default: + State = Default; + break; + } + break; + case tok::coloncolon: + // This can come at the beginning or in the middle of a namespace + // name. + switch (State) { + case UsingNamespace: + NSName.clear(); + LLVM_FALLTHROUGH; + case UsingNamespaceName: + NSName.append("::"); + State = UsingNamespaceName; + break; + case NamespaceName: + NSName.append("::"); + State = NamespaceName; + break; + case Namespace: // Not legal here. + case Using: + case Default: + State = Default; + break; + } + break; + case tok::l_brace: + // Record which { started a namespace, so we know when } ends one. + if (State == NamespaceName) { + // Parsed: namespace { + BraceStack.push_back(true); + Enclosing.push_back(NSName); + Event.Trigger = NamespaceEvent::BeginNamespace; + Event.Payload = llvm::join(Enclosing, "::"); + Callback(Event); + } else { + // This case includes anonymous namespaces (State = Namespace). + // For our purposes, they're not namespaces and we ignore them. + BraceStack.push_back(false); + } + State = Default; + break; + case tok::r_brace: + // If braces are unmatched, we're going to be confused, but don't + // crash. + if (!BraceStack.empty()) { + if (BraceStack.back()) { + // Parsed: } // namespace + Enclosing.pop_back(); + Event.Trigger = NamespaceEvent::EndNamespace; + Event.Payload = llvm::join(Enclosing, "::"); + Callback(Event); } - }); + BraceStack.pop_back(); + } + break; + case tok::semi: + if (State == UsingNamespaceName) { + // Parsed: using namespace ; + Event.Trigger = NamespaceEvent::UsingDirective; + Event.Payload = std::move(NSName); + Callback(Event); + } + State = Default; + break; + default: + State = Default; + break; + } + }); } // Returns the prefix namespaces of NS: {"" ... NS}. @@ -794,12 +792,12 @@ } // namespace std::vector visibleNamespaces(llvm::StringRef Code, - const format::FormatStyle &Style) { + const LangOptions &LangOpts) { std::string Current; // Map from namespace to (resolved) namespaces introduced via using directive. llvm::StringMap> UsingDirectives; - parseNamespaceEvents(Code, Style, [&](NamespaceEvent Event) { + parseNamespaceEvents(Code, LangOpts, [&](NamespaceEvent Event) { llvm::StringRef NS = Event.Payload; switch (Event.Trigger) { case NamespaceEvent::BeginNamespace: @@ -953,14 +951,14 @@ EligibleRegion getEligiblePoints(llvm::StringRef Code, llvm::StringRef FullyQualifiedName, - const format::FormatStyle &Style) { + const LangOptions &LangOpts) { EligibleRegion ER; // Start with global namespace. std::vector Enclosing = {""}; // FIXME: In addition to namespaces try to generate events for function // definitions as well. One might use a closing parantheses(")" followed by an // opening brace "{" to trigger the start. - parseNamespaceEvents(Code, Style, [&](NamespaceEvent Event) { + parseNamespaceEvents(Code, LangOpts, [&](NamespaceEvent Event) { // Using Directives only introduces declarations to current scope, they do // not change the current namespace, so skip them. if (Event.Trigger == NamespaceEvent::UsingDirective) diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -284,10 +284,10 @@ // should also try to follow ordering of declarations. For example, if decls // come in order `foo, bar, baz` then this function should return some point // between foo and baz for inserting bar. -llvm::Expected -getInsertionPoint(llvm::StringRef Contents, llvm::StringRef QualifiedName, - const format::FormatStyle &Style) { - auto Region = getEligiblePoints(Contents, QualifiedName, Style); +llvm::Expected getInsertionPoint(llvm::StringRef Contents, + llvm::StringRef QualifiedName, + const LangOptions &LangOpts) { + auto Region = getEligiblePoints(Contents, QualifiedName, LangOpts); assert(!Region.EligiblePoints.empty()); // FIXME: This selection can be made smarter by looking at the definition @@ -416,9 +416,10 @@ return llvm::createStringError(Buffer.getError(), Buffer.getError().message()); auto Contents = Buffer->get()->getBuffer(); - auto InsertionPoint = - getInsertionPoint(Contents, Source->getQualifiedNameAsString(), - getFormatStyleForFile(*CCFile, Contents, &FS)); + auto LangOpts = format::getFormattingLangOpts( + getFormatStyleForFile(*CCFile, Contents, &FS)); + auto InsertionPoint = getInsertionPoint( + Contents, Source->getQualifiedNameAsString(), LangOpts); if (!InsertionPoint) return InsertionPoint.takeError(); diff --git a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp --- a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp +++ b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp @@ -215,8 +215,9 @@ for (unsigned I = 0; I <= L.Length; ++I) EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, I)), llvm::HasValue(L.Offset + I)); - EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, L.Length+1)), - llvm::HasValue(L.Offset + L.Length)); + EXPECT_THAT_EXPECTED( + positionToOffset(File, position(L.Number, L.Length + 1)), + llvm::HasValue(L.Offset + L.Length)); EXPECT_THAT_EXPECTED( positionToOffset(File, position(L.Number, L.Length + 1), false), llvm::Failed()); // out of range @@ -413,9 +414,10 @@ {""}, }, }; - for (const auto& Case : Cases) { + for (const auto &Case : Cases) { EXPECT_EQ(Case.second, - visibleNamespaces(Case.first, format::getLLVMStyle())) + visibleNamespaces(Case.first, format::getFormattingLangOpts( + format::getLLVMStyle()))) << Case.first; } } @@ -450,7 +452,7 @@ EXPECT_THAT(*Result, MacroName("MACRO")); } -TEST(SourceCodeTests, IsInsideMainFile){ +TEST(SourceCodeTests, IsInsideMainFile) { TestTU TU; TU.HeaderCode = R"cpp( #define DEFINE_CLASS(X) class X {}; @@ -469,7 +471,7 @@ TU.ExtraArgs.push_back("-DHeader=Header3"); TU.ExtraArgs.push_back("-DMain=Main3"); auto AST = TU.build(); - const auto& SM = AST.getSourceManager(); + const auto &SM = AST.getSourceManager(); auto DeclLoc = [&AST](llvm::StringRef Name) { return findDecl(AST, Name).getLocation(); }; @@ -569,7 +571,7 @@ TU.AdditionalFiles["foo.inc"] = "int foo;\n"; TU.AdditionalFiles["bar.inc"] = "int bar;\n"; auto AST = TU.build(); - const auto& SM = AST.getSourceManager(); + const auto &SM = AST.getSourceManager(); FileID Foo = SM.getFileID(findDecl(AST, "foo").getLocation()); EXPECT_EQ(SM.getFileOffset(includeHashLoc(Foo, SM)), @@ -633,8 +635,9 @@ for (auto Case : Cases) { Annotations Test(Case.Code); - auto Res = getEligiblePoints(Test.code(), Case.FullyQualifiedName, - format::getLLVMStyle()); + auto Res = getEligiblePoints( + Test.code(), Case.FullyQualifiedName, + format::getFormattingLangOpts(format::getLLVMStyle())); EXPECT_THAT(Res.EligiblePoints, testing::ElementsAreArray(Test.points())) << Test.code(); EXPECT_EQ(Res.EnclosingNamespace, Case.EnclosingNamespace) << Test.code();