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