}
private:
- // The qualifier to remove. Set by prepare().
+ // All of the following are set by prepare().
+ // The qualifier to remove.
NestedNameSpecifierLoc QualifierToRemove;
- // The name following QualifierToRemove. Set by prepare().
+ // The name following QualifierToRemove.
llvm::StringRef Name;
};
REGISTER_TWEAK(AddUsing)
return false;
}
+std::string getNNSLAsString(NestedNameSpecifierLoc &NNSL,
+ const PrintingPolicy &Policy) {
+ std::string Out;
+ llvm::raw_string_ostream OutStream(Out);
+ NNSL.getNestedNameSpecifier()->print(OutStream, Policy);
+ return OutStream.str();
+}
+
bool AddUsing::prepare(const Selection &Inputs) {
auto &SM = Inputs.AST->getSourceManager();
+ const auto &TB = Inputs.AST->getTokens();
// Do not suggest "using" in header files. That way madness lies.
if (isHeaderFile(SM.getFileEntryForID(SM.getMainFileID())->getName(),
}
} else if (auto *T = Node->ASTNode.get<TypeLoc>()) {
if (auto E = T->getAs<ElaboratedTypeLoc>()) {
- if (auto *BaseTypeIdentifier =
- E.getType().getUnqualifiedType().getBaseTypeIdentifier()) {
- Name = BaseTypeIdentifier->getName();
- QualifierToRemove = E.getQualifierLoc();
- }
+ QualifierToRemove = E.getQualifierLoc();
+
+ auto SpelledTokens =
+ TB.spelledForExpanded(TB.expandedTokens(E.getSourceRange()));
+ if (!SpelledTokens)
+ return false;
+ auto SpelledRange = syntax::Token::range(SM, SpelledTokens->front(),
+ SpelledTokens->back());
+ Name = SpelledRange.text(SM);
+
+ std::string QualifierToRemoveStr = getNNSLAsString(
+ QualifierToRemove, Inputs.AST->getASTContext().getPrintingPolicy());
+ if (!Name.consume_front(QualifierToRemoveStr))
+ return false; // What's spelled doesn't match the qualifier.
}
}
Expected<Tweak::Effect> AddUsing::apply(const Selection &Inputs) {
auto &SM = Inputs.AST->getSourceManager();
- auto &TB = Inputs.AST->getTokens();
- // Determine the length of the qualifier under the cursor, then remove it.
- auto SpelledTokens = TB.spelledForExpanded(
- TB.expandedTokens(QualifierToRemove.getSourceRange()));
- if (!SpelledTokens) {
- return error("Could not determine length of the qualifier");
- }
- unsigned Length =
- syntax::Token::range(SM, SpelledTokens->front(), SpelledTokens->back())
- .length();
+ std::string QualifierToRemoveStr = getNNSLAsString(
+ QualifierToRemove, Inputs.AST->getASTContext().getPrintingPolicy());
tooling::Replacements R;
if (auto Err = R.add(tooling::Replacement(
- SM, SpelledTokens->front().location(), Length, ""))) {
+ SM, SM.getSpellingLoc(QualifierToRemove.getBeginLoc()),
+ QualifierToRemoveStr.length(), ""))) {
return std::move(Err);
}
if (InsertionPoint->AlwaysFullyQualify &&
!isFullyQualified(QualifierToRemove.getNestedNameSpecifier()))
UsingTextStream << "::";
- QualifierToRemove.getNestedNameSpecifier()->print(
- UsingTextStream, Inputs.AST->getASTContext().getPrintingPolicy());
- UsingTextStream << Name << ";" << InsertionPoint->Suffix;
+ UsingTextStream << QualifierToRemoveStr << Name << ";"
+ << InsertionPoint->Suffix;
assert(SM.getFileID(InsertionPoint->Loc) == SM.getMainFileID());
if (auto Err = R.add(tooling::Replacement(SM, InsertionPoint->Loc, 0,
EXPECT_UNAVAILABLE(Header + "void fun() { ::ban::fo^o(); }");
EXPECT_AVAILABLE(Header + "void fun() { banana::fo^o(); }");
+ // Do not offer code action on typo-corrections.
+ EXPECT_UNAVAILABLE(Header + "/*error-ok*/c^c C;");
+
// Check that we do not trigger in header files.
FileName = "test.h";
ExtraArgs.push_back("-xc++-header"); // .h file is treated a C by default.
void fun() {
ff();
+})cpp"},
+ // using alias; insert using for the spelled name.
+ {R"cpp(
+#include "test.hpp"
+
+void fun() {
+ one::u^u u;
+})cpp",
+ R"cpp(
+#include "test.hpp"
+
+using one::uu;
+
+void fun() {
+ uu u;
+})cpp"},
+ // using namespace.
+ {R"cpp(
+#include "test.hpp"
+using namespace one;
+namespace {
+two::c^c C;
+})cpp",
+ R"cpp(
+#include "test.hpp"
+using namespace one;
+namespace {using two::cc;
+
+cc C;
})cpp"}};
llvm::StringMap<std::string> EditedFiles;
for (const auto &Case : Cases) {
static void mm() {}
};
}
+using uu = two::cc;
})cpp";
EXPECT_EQ(apply(SubCase, &EditedFiles), Case.ExpectedSource);
}