Index: clang-tools-extra/trunk/include-fixer/IncludeFixerContext.cpp =================================================================== --- clang-tools-extra/trunk/include-fixer/IncludeFixerContext.cpp +++ clang-tools-extra/trunk/include-fixer/IncludeFixerContext.cpp @@ -15,9 +15,17 @@ namespace { +// Splits a multiply qualified names (e.g. a::b::c). +llvm::SmallVector +SplitQualifiers(llvm::StringRef StringQualifiers) { + llvm::SmallVector Qualifiers; + StringQualifiers.split(Qualifiers, "::"); + return Qualifiers; +} + std::string createQualifiedNameForReplacement( llvm::StringRef RawSymbolName, - llvm::StringRef SymbolScopedQualifiers, + llvm::StringRef SymbolScopedQualifiersName, const find_all_symbols::SymbolInfo &MatchedSymbol) { // No need to add missing qualifiers if SymbolIndentifer has a global scope // operator "::". @@ -32,8 +40,7 @@ // missing stripped qualifiers here. // // Get stripped qualifiers. - llvm::SmallVector SymbolQualifiers; - RawSymbolName.split(SymbolQualifiers, "::"); + auto SymbolQualifiers = SplitQualifiers(RawSymbolName); std::string StrippedQualifiers; while (!SymbolQualifiers.empty() && !llvm::StringRef(QualifiedName).endswith(SymbolQualifiers.back())) { @@ -43,11 +50,26 @@ // Append the missing stripped qualifiers. std::string FullyQualifiedName = QualifiedName + StrippedQualifiers; - // Skips symbol scoped qualifiers prefix. - if (llvm::StringRef(FullyQualifiedName).startswith(SymbolScopedQualifiers)) - return FullyQualifiedName.substr(SymbolScopedQualifiers.size()); - - return FullyQualifiedName; + // Try to find and skip the common prefix qualifiers. + auto FullySymbolQualifiers = SplitQualifiers(FullyQualifiedName); + auto ScopedQualifiers = SplitQualifiers(SymbolScopedQualifiersName); + auto FullySymbolQualifiersIter = FullySymbolQualifiers.begin(); + auto SymbolScopedQualifiersIter = ScopedQualifiers.begin(); + while (FullySymbolQualifiersIter != FullySymbolQualifiers.end() && + SymbolScopedQualifiersIter != ScopedQualifiers.end()) { + if (*FullySymbolQualifiersIter != *SymbolScopedQualifiersIter) + break; + ++FullySymbolQualifiersIter; + ++SymbolScopedQualifiersIter; + } + std::string Result; + for (; FullySymbolQualifiersIter != FullySymbolQualifiers.end(); + ++FullySymbolQualifiersIter) { + if (!Result.empty()) + Result += "::"; + Result += *FullySymbolQualifiersIter; + } + return Result; } } // anonymous namespace Index: clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp +++ clang-tools-extra/trunk/unittests/include-fixer/IncludeFixerTest.cpp @@ -245,6 +245,14 @@ EXPECT_EQ("#include \"bar2.h\"\nnamespace c {\na::c::bar b;\n}\n", runIncludeFixer("namespace c {\nbar b;\n}\n")); + // Test common qualifers reduction. + EXPECT_EQ( + "#include \"bar.h\"\nnamespace a {\nnamespace d {\nb::bar b;\n}\n}\n", + runIncludeFixer("namespace a {\nnamespace d {\nbar b;\n}\n}\n")); + EXPECT_EQ( + "#include \"bar.h\"\nnamespace d {\nnamespace a {\na::b::bar b;\n}\n}\n", + runIncludeFixer("namespace d {\nnamespace a {\nbar b;\n}\n}\n")); + // Test nested classes. EXPECT_EQ("#include \"bar.h\"\nnamespace d {\na::b::bar::t b;\n}\n", runIncludeFixer("namespace d {\nbar::t b;\n}\n"));