diff --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h --- a/clang-tools-extra/clangd/AST.h +++ b/clang-tools-extra/clangd/AST.h @@ -80,19 +80,7 @@ /// Returns a QualType as string. The result doesn't contain unwritten scopes /// like annoymous/inline namespace. -std::string printType(const QualType QT, const DeclContext &Context); - -/// Try to shorten the OriginalName by removing namespaces from the left of -/// the string that are redundant in the CurrentNamespace. This way the type -/// idenfier become shorter and easier to read. -/// Limitation: It only handles the qualifier of the type itself, not that of -/// templates. -/// FIXME: change type of parameter CurrentNamespace to DeclContext , -/// take in to account using directives etc -/// Example: shortenNamespace("ns1::MyClass", "ns1") -/// --> "MyClass" -std::string shortenNamespace(const llvm::StringRef OriginalName, - const llvm::StringRef CurrentNamespace); +std::string printType(const QualType QT, const DeclContext &CurContext); /// Indicates if \p D is a template instantiation implicitly generated by the /// compiler, e.g. @@ -157,7 +145,7 @@ /// present in \p VisibleNamespaces, no matter whether it is from ns1:: or ns2:: std::string getQualification(ASTContext &Context, const DeclContext *DestContext, - SourceLocation InsertionPoint, const NamedDecl *ND, + const NamedDecl *ND, llvm::ArrayRef VisibleNamespaces); } // namespace clangd diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -8,8 +8,10 @@ #include "AST.h" +#include "FindTarget.h" #include "SourceCode.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -299,32 +301,21 @@ return SymbolID(USR); } -std::string shortenNamespace(const llvm::StringRef OriginalName, - const llvm::StringRef CurrentNamespace) { - llvm::SmallVector OriginalParts; - llvm::SmallVector CurrentParts; - llvm::SmallVector Result; - OriginalName.split(OriginalParts, "::"); - CurrentNamespace.split(CurrentParts, "::"); - auto MinLength = std::min(CurrentParts.size(), OriginalParts.size()); - - unsigned DifferentAt = 0; - while (DifferentAt < MinLength && - CurrentParts[DifferentAt] == OriginalParts[DifferentAt]) { - DifferentAt++; - } - - for (unsigned i = DifferentAt; i < OriginalParts.size(); ++i) { - Result.push_back(OriginalParts[i]); - } - return join(Result, "::"); -} - -std::string printType(const QualType QT, const DeclContext &Context) { - PrintingPolicy PP(Context.getParentASTContext().getPrintingPolicy()); - PP.SuppressUnwrittenScope = 1; - PP.SuppressTagKeyword = 1; - return shortenNamespace(QT.getAsString(PP), printNamespaceScope(Context)); +// FIXME: This should be handled while printing underlying decls instead. +std::string printType(const QualType QT, const DeclContext &CurContext) { + std::string Result; + llvm::raw_string_ostream OS(Result); + auto Decls = explicitReferenceTargets( + ast_type_traits::DynTypedNode::create(QT), DeclRelation::Alias); + if (!Decls.empty()) + OS << getQualification(CurContext.getParentASTContext(), &CurContext, + Decls.front(), + /*VisibleNamespaces=*/llvm::ArrayRef{}); + PrintingPolicy PP(CurContext.getParentASTContext().getPrintingPolicy()); + PP.SuppressScope = true; + PP.SuppressTagKeyword = true; + QT.print(OS, PP); + return OS.str(); } QualType declaredType(const TypeDecl *D) { @@ -464,7 +455,7 @@ std::string getQualification(ASTContext &Context, const DeclContext *DestContext, - SourceLocation InsertionPoint, const NamedDecl *ND, + const NamedDecl *ND, llvm::ArrayRef VisibleNamespaces) { for (llvm::StringRef NS : VisibleNamespaces) { assert(NS.endswith("::")); diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp --- a/clang-tools-extra/clangd/unittests/ASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclBase.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include @@ -25,29 +26,6 @@ namespace clangd { namespace { -TEST(ShortenNamespace, All) { - ASSERT_EQ("TestClass", shortenNamespace("TestClass", "")); - - ASSERT_EQ("TestClass", shortenNamespace( - "testnamespace::TestClass", "testnamespace")); - - ASSERT_EQ( - "namespace1::TestClass", - shortenNamespace("namespace1::TestClass", "namespace2")); - - ASSERT_EQ("TestClass", - shortenNamespace("testns1::testns2::TestClass", - "testns1::testns2")); - - ASSERT_EQ( - "testns2::TestClass", - shortenNamespace("testns1::testns2::TestClass", "testns1")); - - ASSERT_EQ("TestClass", - shortenNamespace( - "testns1::TestClass", "testns1")); -} - TEST(GetDeducedType, KwAutoExpansion) { struct Test { StringRef AnnotatedCode; @@ -166,14 +144,70 @@ Case.Qualifications[I]); } else { EXPECT_EQ(getQualification(AST.getASTContext(), - D->getLexicalDeclContext(), D->getBeginLoc(), - TargetDecl, Case.VisibleNamespaces), + D->getLexicalDeclContext(), TargetDecl, + Case.VisibleNamespaces), Case.Qualifications[I]); } } } } +TEST(ClangdAST, PrintType) { + const struct { + llvm::StringRef Test; + std::vector Types; + } Cases[] = { + { + R"cpp( + namespace ns1 { namespace ns2 { class Foo {}; } } + void insert(); // ns1::ns2::Foo + namespace ns1 { + void insert(); // ns2::Foo + namespace ns2 { + void insert(); // Foo + } + } + )cpp", + {"ns1::ns2::Foo", "ns2::Foo", "Foo"}, + }, + { + R"cpp( + namespace ns1 { + typedef int Foo; + } + void insert(); // ns1::Foo + namespace ns1 { + void insert(); // Foo + } + )cpp", + {"ns1::Foo", "Foo"}, + }, + }; + for (const auto &Case : Cases) { + Annotations Test(Case.Test); + TestTU TU = TestTU::withCode(Test.code()); + ParsedAST AST = TU.build(); + std::vector InsertionPoints; + const TypeDecl *TargetDecl = nullptr; + findDecl(AST, [&](const NamedDecl &ND) { + if (ND.getNameAsString() == "Foo") { + if (const auto *TD = llvm::dyn_cast(&ND)) { + TargetDecl = TD; + return true; + } + } else if (ND.getNameAsString() == "insert") + InsertionPoints.push_back(ND.getDeclContext()); + return false; + }); + + ASSERT_EQ(InsertionPoints.size(), Case.Types.size()); + for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) { + const auto *DC = InsertionPoints[I]; + EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC), + Case.Types[I]); + } + } +} } // namespace } // namespace clangd } // namespace clang