xref: /llvm-project/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp (revision df9a14d7bbf1180e4f1474254c9d7ed6bcb4ce55)
143356f56SNico Weber //===-- IncludeFixer.cpp - Include inserter based on sema callbacks -------===//
243356f56SNico Weber //
343356f56SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
443356f56SNico Weber // See https://llvm.org/LICENSE.txt for license information.
543356f56SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
643356f56SNico Weber //
743356f56SNico Weber //===----------------------------------------------------------------------===//
843356f56SNico Weber 
943356f56SNico Weber #include "IncludeFixer.h"
1043356f56SNico Weber #include "clang/Format/Format.h"
1143356f56SNico Weber #include "clang/Frontend/CompilerInstance.h"
1243356f56SNico Weber #include "clang/Lex/HeaderSearch.h"
1343356f56SNico Weber #include "clang/Lex/Preprocessor.h"
1443356f56SNico Weber #include "clang/Parse/ParseAST.h"
1543356f56SNico Weber #include "clang/Sema/Sema.h"
1643356f56SNico Weber #include "llvm/Support/Debug.h"
1743356f56SNico Weber #include "llvm/Support/raw_ostream.h"
1843356f56SNico Weber 
1943356f56SNico Weber #define DEBUG_TYPE "clang-include-fixer"
2043356f56SNico Weber 
2143356f56SNico Weber using namespace clang;
2243356f56SNico Weber 
2343356f56SNico Weber namespace clang {
2443356f56SNico Weber namespace include_fixer {
2543356f56SNico Weber namespace {
2643356f56SNico Weber /// Manages the parse, gathers include suggestions.
2743356f56SNico Weber class Action : public clang::ASTFrontendAction {
2843356f56SNico Weber public:
2943356f56SNico Weber   explicit Action(SymbolIndexManager &SymbolIndexMgr, bool MinimizeIncludePaths)
305b5329bdSChris Bieneman       : SemaSource(new IncludeFixerSemaSource(SymbolIndexMgr,
315b5329bdSChris Bieneman                                               MinimizeIncludePaths,
325b5329bdSChris Bieneman                                               /*GenerateDiagnostics=*/false)) {}
3343356f56SNico Weber 
3443356f56SNico Weber   std::unique_ptr<clang::ASTConsumer>
3543356f56SNico Weber   CreateASTConsumer(clang::CompilerInstance &Compiler,
3643356f56SNico Weber                     StringRef InFile) override {
375b5329bdSChris Bieneman     SemaSource->setFilePath(InFile);
381c705d9cSJonas Devlieghere     return std::make_unique<clang::ASTConsumer>();
3943356f56SNico Weber   }
4043356f56SNico Weber 
4143356f56SNico Weber   void ExecuteAction() override {
4243356f56SNico Weber     clang::CompilerInstance *Compiler = &getCompilerInstance();
4343356f56SNico Weber     assert(!Compiler->hasSema() && "CI already has Sema");
4443356f56SNico Weber 
4543356f56SNico Weber     // Set up our hooks into sema and parse the AST.
4643356f56SNico Weber     if (hasCodeCompletionSupport() &&
4743356f56SNico Weber         !Compiler->getFrontendOpts().CodeCompletionAt.FileName.empty())
4843356f56SNico Weber       Compiler->createCodeCompletionConsumer();
4943356f56SNico Weber 
5043356f56SNico Weber     clang::CodeCompleteConsumer *CompletionConsumer = nullptr;
5143356f56SNico Weber     if (Compiler->hasCodeCompletionConsumer())
5243356f56SNico Weber       CompletionConsumer = &Compiler->getCodeCompletionConsumer();
5343356f56SNico Weber 
5443356f56SNico Weber     Compiler->createSema(getTranslationUnitKind(), CompletionConsumer);
555b5329bdSChris Bieneman     SemaSource->setCompilerInstance(Compiler);
565b5329bdSChris Bieneman     Compiler->getSema().addExternalSource(SemaSource.get());
5743356f56SNico Weber 
5843356f56SNico Weber     clang::ParseAST(Compiler->getSema(), Compiler->getFrontendOpts().ShowStats,
5943356f56SNico Weber                     Compiler->getFrontendOpts().SkipFunctionBodies);
6043356f56SNico Weber   }
6143356f56SNico Weber 
6243356f56SNico Weber   IncludeFixerContext
6343356f56SNico Weber   getIncludeFixerContext(const clang::SourceManager &SourceManager,
6443356f56SNico Weber                          clang::HeaderSearch &HeaderSearch) const {
655b5329bdSChris Bieneman     return SemaSource->getIncludeFixerContext(SourceManager, HeaderSearch,
665b5329bdSChris Bieneman                                               SemaSource->getMatchedSymbols());
6743356f56SNico Weber   }
6843356f56SNico Weber 
6943356f56SNico Weber private:
705b5329bdSChris Bieneman   IntrusiveRefCntPtr<IncludeFixerSemaSource> SemaSource;
7143356f56SNico Weber };
7243356f56SNico Weber 
7343356f56SNico Weber } // namespace
7443356f56SNico Weber 
7543356f56SNico Weber IncludeFixerActionFactory::IncludeFixerActionFactory(
7643356f56SNico Weber     SymbolIndexManager &SymbolIndexMgr,
7743356f56SNico Weber     std::vector<IncludeFixerContext> &Contexts, StringRef StyleName,
7843356f56SNico Weber     bool MinimizeIncludePaths)
7943356f56SNico Weber     : SymbolIndexMgr(SymbolIndexMgr), Contexts(Contexts),
8043356f56SNico Weber       MinimizeIncludePaths(MinimizeIncludePaths) {}
8143356f56SNico Weber 
8243356f56SNico Weber IncludeFixerActionFactory::~IncludeFixerActionFactory() = default;
8343356f56SNico Weber 
8443356f56SNico Weber bool IncludeFixerActionFactory::runInvocation(
8543356f56SNico Weber     std::shared_ptr<clang::CompilerInvocation> Invocation,
8643356f56SNico Weber     clang::FileManager *Files,
8743356f56SNico Weber     std::shared_ptr<clang::PCHContainerOperations> PCHContainerOps,
8843356f56SNico Weber     clang::DiagnosticConsumer *Diagnostics) {
8943356f56SNico Weber   assert(Invocation->getFrontendOpts().Inputs.size() == 1);
9043356f56SNico Weber 
9143356f56SNico Weber   // Set up Clang.
9243356f56SNico Weber   clang::CompilerInstance Compiler(PCHContainerOps);
9343356f56SNico Weber   Compiler.setInvocation(std::move(Invocation));
9443356f56SNico Weber   Compiler.setFileManager(Files);
9543356f56SNico Weber 
9643356f56SNico Weber   // Create the compiler's actual diagnostics engine. We want to drop all
9743356f56SNico Weber   // diagnostics here.
98*df9a14d7SKadir Cetinkaya   Compiler.createDiagnostics(Files->getVirtualFileSystem(),
99*df9a14d7SKadir Cetinkaya                              new clang::IgnoringDiagConsumer,
10043356f56SNico Weber                              /*ShouldOwnClient=*/true);
10143356f56SNico Weber   Compiler.createSourceManager(*Files);
10243356f56SNico Weber 
10343356f56SNico Weber   // We abort on fatal errors so don't let a large number of errors become
10443356f56SNico Weber   // fatal. A missing #include can cause thousands of errors.
10543356f56SNico Weber   Compiler.getDiagnostics().setErrorLimit(0);
10643356f56SNico Weber 
10743356f56SNico Weber   // Run the parser, gather missing includes.
10843356f56SNico Weber   auto ScopedToolAction =
1091c705d9cSJonas Devlieghere       std::make_unique<Action>(SymbolIndexMgr, MinimizeIncludePaths);
11043356f56SNico Weber   Compiler.ExecuteAction(*ScopedToolAction);
11143356f56SNico Weber 
11243356f56SNico Weber   Contexts.push_back(ScopedToolAction->getIncludeFixerContext(
11343356f56SNico Weber       Compiler.getSourceManager(),
11443356f56SNico Weber       Compiler.getPreprocessor().getHeaderSearchInfo()));
11543356f56SNico Weber 
11643356f56SNico Weber   // Technically this should only return true if we're sure that we have a
11743356f56SNico Weber   // parseable file. We don't know that though. Only inform users of fatal
11843356f56SNico Weber   // errors.
11943356f56SNico Weber   return !Compiler.getDiagnostics().hasFatalErrorOccurred();
12043356f56SNico Weber }
12143356f56SNico Weber 
12243356f56SNico Weber static bool addDiagnosticsForContext(TypoCorrection &Correction,
12343356f56SNico Weber                                      const IncludeFixerContext &Context,
12443356f56SNico Weber                                      StringRef Code, SourceLocation StartOfFile,
12543356f56SNico Weber                                      ASTContext &Ctx) {
12643356f56SNico Weber   auto Reps = createIncludeFixerReplacements(
12743356f56SNico Weber       Code, Context, format::getLLVMStyle(), /*AddQualifiers=*/false);
12843356f56SNico Weber   if (!Reps || Reps->size() != 1)
12943356f56SNico Weber     return false;
13043356f56SNico Weber 
13143356f56SNico Weber   unsigned DiagID = Ctx.getDiagnostics().getCustomDiagID(
13243356f56SNico Weber       DiagnosticsEngine::Note, "Add '#include %0' to provide the missing "
13343356f56SNico Weber                                "declaration [clang-include-fixer]");
13443356f56SNico Weber 
13543356f56SNico Weber   // FIXME: Currently we only generate a diagnostic for the first header. Give
13643356f56SNico Weber   // the user choices.
13743356f56SNico Weber   const tooling::Replacement &Placed = *Reps->begin();
13843356f56SNico Weber 
13943356f56SNico Weber   auto Begin = StartOfFile.getLocWithOffset(Placed.getOffset());
14043356f56SNico Weber   auto End = Begin.getLocWithOffset(std::max(0, (int)Placed.getLength() - 1));
14143356f56SNico Weber   PartialDiagnostic PD(DiagID, Ctx.getDiagAllocator());
14243356f56SNico Weber   PD << Context.getHeaderInfos().front().Header
14343356f56SNico Weber      << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Begin, End),
14443356f56SNico Weber                                      Placed.getReplacementText());
14543356f56SNico Weber   Correction.addExtraDiagnostic(std::move(PD));
14643356f56SNico Weber   return true;
14743356f56SNico Weber }
14843356f56SNico Weber 
14943356f56SNico Weber /// Callback for incomplete types. If we encounter a forward declaration we
15043356f56SNico Weber /// have the fully qualified name ready. Just query that.
15143356f56SNico Weber bool IncludeFixerSemaSource::MaybeDiagnoseMissingCompleteType(
15243356f56SNico Weber     clang::SourceLocation Loc, clang::QualType T) {
15343356f56SNico Weber   // Ignore spurious callbacks from SFINAE contexts.
15443356f56SNico Weber   if (CI->getSema().isSFINAEContext())
15543356f56SNico Weber     return false;
15643356f56SNico Weber 
15743356f56SNico Weber   clang::ASTContext &context = CI->getASTContext();
15843356f56SNico Weber   std::string QueryString = QualType(T->getUnqualifiedDesugaredType(), 0)
15943356f56SNico Weber                                 .getAsString(context.getPrintingPolicy());
16043356f56SNico Weber   LLVM_DEBUG(llvm::dbgs() << "Query missing complete type '" << QueryString
16143356f56SNico Weber                           << "'");
16243356f56SNico Weber   // Pass an empty range here since we don't add qualifier in this case.
16343356f56SNico Weber   std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
16443356f56SNico Weber       query(QueryString, "", tooling::Range());
16543356f56SNico Weber 
16643356f56SNico Weber   if (!MatchedSymbols.empty() && GenerateDiagnostics) {
16743356f56SNico Weber     TypoCorrection Correction;
16843356f56SNico Weber     FileID FID = CI->getSourceManager().getFileID(Loc);
16943356f56SNico Weber     StringRef Code = CI->getSourceManager().getBufferData(FID);
17043356f56SNico Weber     SourceLocation StartOfFile =
17143356f56SNico Weber         CI->getSourceManager().getLocForStartOfFile(FID);
17243356f56SNico Weber     addDiagnosticsForContext(
17343356f56SNico Weber         Correction,
17443356f56SNico Weber         getIncludeFixerContext(CI->getSourceManager(),
17543356f56SNico Weber                                CI->getPreprocessor().getHeaderSearchInfo(),
17643356f56SNico Weber                                MatchedSymbols),
17743356f56SNico Weber         Code, StartOfFile, CI->getASTContext());
17843356f56SNico Weber     for (const PartialDiagnostic &PD : Correction.getExtraDiagnostics())
17943356f56SNico Weber       CI->getSema().Diag(Loc, PD);
18043356f56SNico Weber   }
18143356f56SNico Weber   return true;
18243356f56SNico Weber }
18343356f56SNico Weber 
18443356f56SNico Weber /// Callback for unknown identifiers. Try to piece together as much
18543356f56SNico Weber /// qualification as we can get and do a query.
18643356f56SNico Weber clang::TypoCorrection IncludeFixerSemaSource::CorrectTypo(
18743356f56SNico Weber     const DeclarationNameInfo &Typo, int LookupKind, Scope *S, CXXScopeSpec *SS,
18843356f56SNico Weber     CorrectionCandidateCallback &CCC, DeclContext *MemberContext,
18943356f56SNico Weber     bool EnteringContext, const ObjCObjectPointerType *OPT) {
19043356f56SNico Weber   // Ignore spurious callbacks from SFINAE contexts.
19143356f56SNico Weber   if (CI->getSema().isSFINAEContext())
19243356f56SNico Weber     return clang::TypoCorrection();
19343356f56SNico Weber 
19443356f56SNico Weber   // We currently ignore the unidentified symbol which is not from the
19543356f56SNico Weber   // main file.
19643356f56SNico Weber   //
19743356f56SNico Weber   // However, this is not always true due to templates in a non-self contained
19843356f56SNico Weber   // header, consider the case:
19943356f56SNico Weber   //
20043356f56SNico Weber   //   // header.h
20143356f56SNico Weber   //   template <typename T>
20243356f56SNico Weber   //   class Foo {
20343356f56SNico Weber   //     T t;
20443356f56SNico Weber   //   };
20543356f56SNico Weber   //
20643356f56SNico Weber   //   // test.cc
20743356f56SNico Weber   //   // We need to add <bar.h> in test.cc instead of header.h.
20843356f56SNico Weber   //   class Bar;
20943356f56SNico Weber   //   Foo<Bar> foo;
21043356f56SNico Weber   //
21143356f56SNico Weber   // FIXME: Add the missing header to the header file where the symbol comes
21243356f56SNico Weber   // from.
21343356f56SNico Weber   if (!CI->getSourceManager().isWrittenInMainFile(Typo.getLoc()))
21443356f56SNico Weber     return clang::TypoCorrection();
21543356f56SNico Weber 
21643356f56SNico Weber   std::string TypoScopeString;
21743356f56SNico Weber   if (S) {
21843356f56SNico Weber     // FIXME: Currently we only use namespace contexts. Use other context
21943356f56SNico Weber     // types for query.
22043356f56SNico Weber     for (const auto *Context = S->getEntity(); Context;
22143356f56SNico Weber          Context = Context->getParent()) {
22243356f56SNico Weber       if (const auto *ND = dyn_cast<NamespaceDecl>(Context)) {
22343356f56SNico Weber         if (!ND->getName().empty())
22443356f56SNico Weber           TypoScopeString = ND->getNameAsString() + "::" + TypoScopeString;
22543356f56SNico Weber       }
22643356f56SNico Weber     }
22743356f56SNico Weber   }
22843356f56SNico Weber 
22943356f56SNico Weber   auto ExtendNestedNameSpecifier = [this](CharSourceRange Range) {
23043356f56SNico Weber     StringRef Source =
23143356f56SNico Weber         Lexer::getSourceText(Range, CI->getSourceManager(), CI->getLangOpts());
23243356f56SNico Weber 
23343356f56SNico Weber     // Skip forward until we find a character that's neither identifier nor
23443356f56SNico Weber     // colon. This is a bit of a hack around the fact that we will only get a
23543356f56SNico Weber     // single callback for a long nested name if a part of the beginning is
23643356f56SNico Weber     // unknown. For example:
23743356f56SNico Weber     //
23843356f56SNico Weber     // llvm::sys::path::parent_path(...)
23943356f56SNico Weber     // ^~~~  ^~~
24043356f56SNico Weber     //    known
24143356f56SNico Weber     //            ^~~~
24243356f56SNico Weber     //      unknown, last callback
24343356f56SNico Weber     //                  ^~~~~~~~~~~
24443356f56SNico Weber     //                  no callback
24543356f56SNico Weber     //
24643356f56SNico Weber     // With the extension we get the full nested name specifier including
24743356f56SNico Weber     // parent_path.
24843356f56SNico Weber     // FIXME: Don't rely on source text.
24943356f56SNico Weber     const char *End = Source.end();
250601102d2SCorentin Jabot     while (isAsciiIdentifierContinue(*End) || *End == ':')
25143356f56SNico Weber       ++End;
25243356f56SNico Weber 
25343356f56SNico Weber     return std::string(Source.begin(), End);
25443356f56SNico Weber   };
25543356f56SNico Weber 
25643356f56SNico Weber   /// If we have a scope specification, use that to get more precise results.
25743356f56SNico Weber   std::string QueryString;
25843356f56SNico Weber   tooling::Range SymbolRange;
25943356f56SNico Weber   const auto &SM = CI->getSourceManager();
26043356f56SNico Weber   auto CreateToolingRange = [&QueryString, &SM](SourceLocation BeginLoc) {
26143356f56SNico Weber     return tooling::Range(SM.getDecomposedLoc(BeginLoc).second,
26243356f56SNico Weber                           QueryString.size());
26343356f56SNico Weber   };
26443356f56SNico Weber   if (SS && SS->getRange().isValid()) {
26543356f56SNico Weber     auto Range = CharSourceRange::getTokenRange(SS->getRange().getBegin(),
26643356f56SNico Weber                                                 Typo.getLoc());
26743356f56SNico Weber 
26843356f56SNico Weber     QueryString = ExtendNestedNameSpecifier(Range);
26943356f56SNico Weber     SymbolRange = CreateToolingRange(Range.getBegin());
27043356f56SNico Weber   } else if (Typo.getName().isIdentifier() && !Typo.getLoc().isMacroID()) {
27143356f56SNico Weber     auto Range =
27243356f56SNico Weber         CharSourceRange::getTokenRange(Typo.getBeginLoc(), Typo.getEndLoc());
27343356f56SNico Weber 
27443356f56SNico Weber     QueryString = ExtendNestedNameSpecifier(Range);
27543356f56SNico Weber     SymbolRange = CreateToolingRange(Range.getBegin());
27643356f56SNico Weber   } else {
27743356f56SNico Weber     QueryString = Typo.getAsString();
27843356f56SNico Weber     SymbolRange = CreateToolingRange(Typo.getLoc());
27943356f56SNico Weber   }
28043356f56SNico Weber 
28143356f56SNico Weber   LLVM_DEBUG(llvm::dbgs() << "TypoScopeQualifiers: " << TypoScopeString
28243356f56SNico Weber                           << "\n");
28343356f56SNico Weber   std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
28443356f56SNico Weber       query(QueryString, TypoScopeString, SymbolRange);
28543356f56SNico Weber 
28643356f56SNico Weber   if (!MatchedSymbols.empty() && GenerateDiagnostics) {
28743356f56SNico Weber     TypoCorrection Correction(Typo.getName());
28843356f56SNico Weber     Correction.setCorrectionRange(SS, Typo);
28943356f56SNico Weber     FileID FID = SM.getFileID(Typo.getLoc());
29043356f56SNico Weber     StringRef Code = SM.getBufferData(FID);
29143356f56SNico Weber     SourceLocation StartOfFile = SM.getLocForStartOfFile(FID);
29243356f56SNico Weber     if (addDiagnosticsForContext(
29343356f56SNico Weber             Correction, getIncludeFixerContext(
29443356f56SNico Weber                             SM, CI->getPreprocessor().getHeaderSearchInfo(),
29543356f56SNico Weber                             MatchedSymbols),
29643356f56SNico Weber             Code, StartOfFile, CI->getASTContext()))
29743356f56SNico Weber       return Correction;
29843356f56SNico Weber   }
29943356f56SNico Weber   return TypoCorrection();
30043356f56SNico Weber }
30143356f56SNico Weber 
30243356f56SNico Weber /// Get the minimal include for a given path.
30343356f56SNico Weber std::string IncludeFixerSemaSource::minimizeInclude(
30443356f56SNico Weber     StringRef Include, const clang::SourceManager &SourceManager,
30543356f56SNico Weber     clang::HeaderSearch &HeaderSearch) const {
30643356f56SNico Weber   if (!MinimizeIncludePaths)
307adcd0268SBenjamin Kramer     return std::string(Include);
30843356f56SNico Weber 
30943356f56SNico Weber   // Get the FileEntry for the include.
31043356f56SNico Weber   StringRef StrippedInclude = Include.trim("\"<>");
3116966c06bSJan Svoboda   auto Entry =
3126966c06bSJan Svoboda       SourceManager.getFileManager().getOptionalFileRef(StrippedInclude);
31343356f56SNico Weber 
31443356f56SNico Weber   // If the file doesn't exist return the path from the database.
31543356f56SNico Weber   // FIXME: This should never happen.
31643356f56SNico Weber   if (!Entry)
317adcd0268SBenjamin Kramer     return std::string(Include);
31843356f56SNico Weber 
3199fe632baSDavid Goldman   bool IsAngled = false;
32043356f56SNico Weber   std::string Suggestion =
3219fe632baSDavid Goldman       HeaderSearch.suggestPathToFileForDiagnostics(*Entry, "", &IsAngled);
32243356f56SNico Weber 
3239fe632baSDavid Goldman   return IsAngled ? '<' + Suggestion + '>' : '"' + Suggestion + '"';
32443356f56SNico Weber }
32543356f56SNico Weber 
32643356f56SNico Weber /// Get the include fixer context for the queried symbol.
32743356f56SNico Weber IncludeFixerContext IncludeFixerSemaSource::getIncludeFixerContext(
32843356f56SNico Weber     const clang::SourceManager &SourceManager,
32943356f56SNico Weber     clang::HeaderSearch &HeaderSearch,
33043356f56SNico Weber     ArrayRef<find_all_symbols::SymbolInfo> MatchedSymbols) const {
33143356f56SNico Weber   std::vector<find_all_symbols::SymbolInfo> SymbolCandidates;
33243356f56SNico Weber   for (const auto &Symbol : MatchedSymbols) {
33343356f56SNico Weber     std::string FilePath = Symbol.getFilePath().str();
33443356f56SNico Weber     std::string MinimizedFilePath = minimizeInclude(
33543356f56SNico Weber         ((FilePath[0] == '"' || FilePath[0] == '<') ? FilePath
33643356f56SNico Weber                                                     : "\"" + FilePath + "\""),
33743356f56SNico Weber         SourceManager, HeaderSearch);
33843356f56SNico Weber     SymbolCandidates.emplace_back(Symbol.getName(), Symbol.getSymbolKind(),
33943356f56SNico Weber                                   MinimizedFilePath, Symbol.getContexts());
34043356f56SNico Weber   }
34143356f56SNico Weber   return IncludeFixerContext(FilePath, QuerySymbolInfos, SymbolCandidates);
34243356f56SNico Weber }
34343356f56SNico Weber 
34443356f56SNico Weber std::vector<find_all_symbols::SymbolInfo>
34543356f56SNico Weber IncludeFixerSemaSource::query(StringRef Query, StringRef ScopedQualifiers,
34643356f56SNico Weber                               tooling::Range Range) {
34743356f56SNico Weber   assert(!Query.empty() && "Empty query!");
34843356f56SNico Weber 
34943356f56SNico Weber   // Save all instances of an unidentified symbol.
35043356f56SNico Weber   //
35143356f56SNico Weber   // We use conservative behavior for detecting the same unidentified symbol
35243356f56SNico Weber   // here. The symbols which have the same ScopedQualifier and RawIdentifier
35343356f56SNico Weber   // are considered equal. So that clang-include-fixer avoids false positives,
35443356f56SNico Weber   // and always adds missing qualifiers to correct symbols.
35543356f56SNico Weber   if (!GenerateDiagnostics && !QuerySymbolInfos.empty()) {
35643356f56SNico Weber     if (ScopedQualifiers == QuerySymbolInfos.front().ScopedQualifiers &&
35743356f56SNico Weber         Query == QuerySymbolInfos.front().RawIdentifier) {
358adcd0268SBenjamin Kramer       QuerySymbolInfos.push_back(
359adcd0268SBenjamin Kramer           {Query.str(), std::string(ScopedQualifiers), Range});
36043356f56SNico Weber     }
36143356f56SNico Weber     return {};
36243356f56SNico Weber   }
36343356f56SNico Weber 
36443356f56SNico Weber   LLVM_DEBUG(llvm::dbgs() << "Looking up '" << Query << "' at ");
36543356f56SNico Weber   LLVM_DEBUG(CI->getSourceManager()
36643356f56SNico Weber                  .getLocForStartOfFile(CI->getSourceManager().getMainFileID())
36743356f56SNico Weber                  .getLocWithOffset(Range.getOffset())
36843356f56SNico Weber                  .print(llvm::dbgs(), CI->getSourceManager()));
36943356f56SNico Weber   LLVM_DEBUG(llvm::dbgs() << " ...");
37043356f56SNico Weber   llvm::StringRef FileName = CI->getSourceManager().getFilename(
37143356f56SNico Weber       CI->getSourceManager().getLocForStartOfFile(
37243356f56SNico Weber           CI->getSourceManager().getMainFileID()));
37343356f56SNico Weber 
374adcd0268SBenjamin Kramer   QuerySymbolInfos.push_back(
375adcd0268SBenjamin Kramer       {Query.str(), std::string(ScopedQualifiers), Range});
37643356f56SNico Weber 
37743356f56SNico Weber   // Query the symbol based on C++ name Lookup rules.
37843356f56SNico Weber   // Firstly, lookup the identifier with scoped namespace contexts;
37943356f56SNico Weber   // If that fails, falls back to look up the identifier directly.
38043356f56SNico Weber   //
38143356f56SNico Weber   // For example:
38243356f56SNico Weber   //
38343356f56SNico Weber   // namespace a {
38443356f56SNico Weber   // b::foo f;
38543356f56SNico Weber   // }
38643356f56SNico Weber   //
38743356f56SNico Weber   // 1. lookup a::b::foo.
38843356f56SNico Weber   // 2. lookup b::foo.
38943356f56SNico Weber   std::string QueryString = ScopedQualifiers.str() + Query.str();
39043356f56SNico Weber   // It's unsafe to do nested search for the identifier with scoped namespace
39143356f56SNico Weber   // context, it might treat the identifier as a nested class of the scoped
39243356f56SNico Weber   // namespace.
39343356f56SNico Weber   std::vector<find_all_symbols::SymbolInfo> MatchedSymbols =
39443356f56SNico Weber       SymbolIndexMgr.search(QueryString, /*IsNestedSearch=*/false, FileName);
39543356f56SNico Weber   if (MatchedSymbols.empty())
39643356f56SNico Weber     MatchedSymbols =
39743356f56SNico Weber         SymbolIndexMgr.search(Query, /*IsNestedSearch=*/true, FileName);
39843356f56SNico Weber   LLVM_DEBUG(llvm::dbgs() << "Having found " << MatchedSymbols.size()
39943356f56SNico Weber                           << " symbols\n");
40043356f56SNico Weber   // We store a copy of MatchedSymbols in a place where it's globally reachable.
40143356f56SNico Weber   // This is used by the standalone version of the tool.
40243356f56SNico Weber   this->MatchedSymbols = MatchedSymbols;
40343356f56SNico Weber   return MatchedSymbols;
40443356f56SNico Weber }
40543356f56SNico Weber 
40643356f56SNico Weber llvm::Expected<tooling::Replacements> createIncludeFixerReplacements(
40743356f56SNico Weber     StringRef Code, const IncludeFixerContext &Context,
40843356f56SNico Weber     const clang::format::FormatStyle &Style, bool AddQualifiers) {
40943356f56SNico Weber   if (Context.getHeaderInfos().empty())
41043356f56SNico Weber     return tooling::Replacements();
41143356f56SNico Weber   StringRef FilePath = Context.getFilePath();
41243356f56SNico Weber   std::string IncludeName =
41343356f56SNico Weber       "#include " + Context.getHeaderInfos().front().Header + "\n";
41443356f56SNico Weber   // Create replacements for the new header.
41543356f56SNico Weber   clang::tooling::Replacements Insertions;
41643356f56SNico Weber   auto Err =
41743356f56SNico Weber       Insertions.add(tooling::Replacement(FilePath, UINT_MAX, 0, IncludeName));
41843356f56SNico Weber   if (Err)
41943356f56SNico Weber     return std::move(Err);
42043356f56SNico Weber 
42143356f56SNico Weber   auto CleanReplaces = cleanupAroundReplacements(Code, Insertions, Style);
42243356f56SNico Weber   if (!CleanReplaces)
42343356f56SNico Weber     return CleanReplaces;
42443356f56SNico Weber 
42543356f56SNico Weber   auto Replaces = std::move(*CleanReplaces);
42643356f56SNico Weber   if (AddQualifiers) {
42743356f56SNico Weber     for (const auto &Info : Context.getQuerySymbolInfos()) {
42843356f56SNico Weber       // Ignore the empty range.
42943356f56SNico Weber       if (Info.Range.getLength() > 0) {
43043356f56SNico Weber         auto R = tooling::Replacement(
43143356f56SNico Weber             {FilePath, Info.Range.getOffset(), Info.Range.getLength(),
43243356f56SNico Weber              Context.getHeaderInfos().front().QualifiedName});
43343356f56SNico Weber         auto Err = Replaces.add(R);
43443356f56SNico Weber         if (Err) {
43543356f56SNico Weber           llvm::consumeError(std::move(Err));
43643356f56SNico Weber           R = tooling::Replacement(
43743356f56SNico Weber               R.getFilePath(), Replaces.getShiftedCodePosition(R.getOffset()),
43843356f56SNico Weber               R.getLength(), R.getReplacementText());
43943356f56SNico Weber           Replaces = Replaces.merge(tooling::Replacements(R));
44043356f56SNico Weber         }
44143356f56SNico Weber       }
44243356f56SNico Weber     }
44343356f56SNico Weber   }
44443356f56SNico Weber   return formatReplacements(Code, Replaces, Style);
44543356f56SNico Weber }
44643356f56SNico Weber 
44743356f56SNico Weber } // namespace include_fixer
44843356f56SNico Weber } // namespace clang
449