1 //===--- IncludeFixer.h ------------------------------------------*- C++-*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INCLUDEFIXER_H 10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INCLUDEFIXER_H 11 12 #include "Diagnostics.h" 13 #include "Headers.h" 14 #include "index/Index.h" 15 #include "index/Symbol.h" 16 #include "clang/AST/Type.h" 17 #include "clang/Basic/Diagnostic.h" 18 #include "clang/Basic/SourceLocation.h" 19 #include "clang/Sema/ExternalSemaSource.h" 20 #include "clang/Tooling/Inclusions/HeaderIncludes.h" 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/IntrusiveRefCntPtr.h" 23 #include "llvm/ADT/StringMap.h" 24 #include "llvm/ADT/StringRef.h" 25 #include <memory> 26 #include <optional> 27 28 namespace clang { 29 namespace clangd { 30 31 /// Attempts to recover from error diagnostics by suggesting include insertion 32 /// fixes. For example, member access into incomplete type can be fixes by 33 /// include headers with the definition. 34 class IncludeFixer { 35 public: IncludeFixer(llvm::StringRef File,std::shared_ptr<IncludeInserter> Inserter,const SymbolIndex & Index,unsigned IndexRequestLimit,Symbol::IncludeDirective Directive)36 IncludeFixer(llvm::StringRef File, std::shared_ptr<IncludeInserter> Inserter, 37 const SymbolIndex &Index, unsigned IndexRequestLimit, 38 Symbol::IncludeDirective Directive) 39 : File(File), Inserter(std::move(Inserter)), Index(Index), 40 IndexRequestLimit(IndexRequestLimit), Directive(Directive) {} 41 42 /// Returns include insertions that can potentially recover the diagnostic. 43 /// If Info is a note and fixes are returned, they should *replace* the note. 44 std::vector<Fix> fix(DiagnosticsEngine::Level DiagLevel, 45 const clang::Diagnostic &Info) const; 46 47 /// Returns an ExternalSemaSource that records failed name lookups in Sema. 48 /// This allows IncludeFixer to suggest inserting headers that define those 49 /// names. 50 llvm::IntrusiveRefCntPtr<ExternalSemaSource> unresolvedNameRecorder(); 51 52 private: 53 /// Attempts to recover diagnostic caused by an incomplete type \p T. 54 std::vector<Fix> fixIncompleteType(const Type &T) const; 55 56 /// Generates header insertion fixes for all symbols. Fixes are deduplicated. 57 std::vector<Fix> fixesForSymbols(const SymbolSlab &Syms) const; 58 59 std::optional<Fix> insertHeader(llvm::StringRef Name, 60 llvm::StringRef Symbol = "", 61 tooling::IncludeDirective Directive = 62 tooling::IncludeDirective::Include) const; 63 64 struct UnresolvedName { 65 std::string Name; // E.g. "X" in foo::X. 66 SourceLocation Loc; // Start location of the unresolved name. 67 std::vector<std::string> Scopes; // Namespace scopes we should search in. 68 }; 69 70 /// Records the last unresolved name seen by Sema. 71 class UnresolvedNameRecorder; 72 73 /// Attempts to fix the unresolved name associated with the current 74 /// diagnostic. We assume a diagnostic is caused by a unresolved name when 75 /// they have the same source location and the unresolved name is the last 76 /// one we've seen during the Sema run. 77 std::vector<Fix> fixUnresolvedName() const; 78 79 std::string File; 80 std::shared_ptr<IncludeInserter> Inserter; 81 const SymbolIndex &Index; 82 const unsigned IndexRequestLimit; // Make at most 5 index requests. 83 mutable unsigned IndexRequestCount = 0; 84 const Symbol::IncludeDirective Directive; 85 86 // These collect the last unresolved name so that we can associate it with the 87 // diagnostic. 88 std::optional<UnresolvedName> LastUnresolvedName; 89 90 // There can be multiple diagnostics that are caused by the same unresolved 91 // name or incomplete type in one parse, especially when code is 92 // copy-and-pasted without #includes. We cache the index results based on 93 // index requests. 94 mutable llvm::StringMap<SymbolSlab> FuzzyFindCache; 95 mutable llvm::DenseMap<SymbolID, SymbolSlab> LookupCache; 96 // Returns std::nullopt if the number of index requests has reached the limit. 97 std::optional<const SymbolSlab *> 98 fuzzyFindCached(const FuzzyFindRequest &Req) const; 99 std::optional<const SymbolSlab *> lookupCached(const SymbolID &ID) const; 100 }; 101 102 } // namespace clangd 103 } // namespace clang 104 105 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INCLUDEFIXER_H 106