2019-01-28 22:01:55 +08:00
|
|
|
//===--- IncludeFixer.h ------------------------------------------*- C++-*-===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INCLUDE_FIXER_H
|
|
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INCLUDE_FIXER_H
|
|
|
|
|
|
|
|
#include "Diagnostics.h"
|
|
|
|
#include "Headers.h"
|
|
|
|
#include "index/Index.h"
|
2019-02-28 21:23:03 +08:00
|
|
|
#include "index/Symbol.h"
|
2019-01-28 22:01:55 +08:00
|
|
|
#include "clang/AST/Type.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2019-02-07 17:23:22 +08:00
|
|
|
#include "clang/Basic/SourceLocation.h"
|
|
|
|
#include "clang/Sema/ExternalSemaSource.h"
|
|
|
|
#include "clang/Sema/Sema.h"
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
|
|
|
#include "llvm/ADT/Optional.h"
|
2019-02-18 21:12:10 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2019-01-28 22:01:55 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
|
|
|
|
/// Attempts to recover from error diagnostics by suggesting include insertion
|
|
|
|
/// fixes. For example, member access into incomplete type can be fixes by
|
|
|
|
/// include headers with the definition.
|
|
|
|
class IncludeFixer {
|
|
|
|
public:
|
|
|
|
IncludeFixer(llvm::StringRef File, std::shared_ptr<IncludeInserter> Inserter,
|
|
|
|
const SymbolIndex &Index, unsigned IndexRequestLimit)
|
|
|
|
: File(File), Inserter(std::move(Inserter)), Index(Index),
|
|
|
|
IndexRequestLimit(IndexRequestLimit) {}
|
|
|
|
|
|
|
|
/// Returns include insertions that can potentially recover the diagnostic.
|
|
|
|
std::vector<Fix> fix(DiagnosticsEngine::Level DiagLevel,
|
|
|
|
const clang::Diagnostic &Info) const;
|
|
|
|
|
2019-02-07 17:23:22 +08:00
|
|
|
/// Returns an ExternalSemaSource that records failed name lookups in Sema.
|
|
|
|
/// This allows IncludeFixer to suggest inserting headers that define those
|
|
|
|
/// names.
|
|
|
|
llvm::IntrusiveRefCntPtr<ExternalSemaSource> unresolvedNameRecorder();
|
|
|
|
|
2019-01-28 22:01:55 +08:00
|
|
|
private:
|
|
|
|
/// Attempts to recover diagnostic caused by an incomplete type \p T.
|
|
|
|
std::vector<Fix> fixIncompleteType(const Type &T) const;
|
|
|
|
|
2019-02-07 17:23:22 +08:00
|
|
|
/// Generates header insertion fixes for all symbols. Fixes are deduplicated.
|
2019-02-18 21:12:10 +08:00
|
|
|
std::vector<Fix> fixesForSymbols(const SymbolSlab &Syms) const;
|
2019-02-07 17:23:22 +08:00
|
|
|
|
|
|
|
struct UnresolvedName {
|
|
|
|
std::string Name; // E.g. "X" in foo::X.
|
|
|
|
SourceLocation Loc; // Start location of the unresolved name.
|
[clangd] Compute scopes eagerly in IncludeFixer
Summary:
Computing lazily leads to crashes. In particular, computing scopes may
produce diagnostics (from inside template instantiations) and we
currently do it when processing another diagnostic, which leads to
crashes.
Moreover, we remember and access 'Scope*' when computing scopes. This
might lead to invalid memory access if the Scope is deleted by the time
we run the delayed computation. We did not actually construct an example
when this happens, though.
From the VCS and review history, it seems the optimization was
introduced in the initial version without a mention of any performance
benchmarks justifying the performance gains. This led me to a
conclusion that the optimization was premature, so removing it to avoid
crashes seems like the right trade-off at that point.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D65796
llvm-svn: 368019
2019-08-06 19:37:50 +08:00
|
|
|
std::vector<std::string> Scopes; // Namespace scopes we should search in.
|
2019-02-07 17:23:22 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Records the last unresolved name seen by Sema.
|
|
|
|
class UnresolvedNameRecorder;
|
|
|
|
|
|
|
|
/// Attempts to fix the unresolved name associated with the current
|
|
|
|
/// diagnostic. We assume a diagnostic is caused by a unresolved name when
|
|
|
|
/// they have the same source location and the unresolved name is the last
|
|
|
|
/// one we've seen during the Sema run.
|
|
|
|
std::vector<Fix> fixUnresolvedName() const;
|
2019-01-28 22:01:55 +08:00
|
|
|
|
|
|
|
std::string File;
|
|
|
|
std::shared_ptr<IncludeInserter> Inserter;
|
|
|
|
const SymbolIndex &Index;
|
|
|
|
const unsigned IndexRequestLimit; // Make at most 5 index requests.
|
|
|
|
mutable unsigned IndexRequestCount = 0;
|
2019-02-07 17:23:22 +08:00
|
|
|
|
|
|
|
// These collect the last unresolved name so that we can associate it with the
|
|
|
|
// diagnostic.
|
|
|
|
llvm::Optional<UnresolvedName> LastUnresolvedName;
|
2019-02-18 21:12:10 +08:00
|
|
|
|
|
|
|
// There can be multiple diagnostics that are caused by the same unresolved
|
|
|
|
// name or incomplete type in one parse, especially when code is
|
|
|
|
// copy-and-pasted without #includes. We cache the index results based on
|
|
|
|
// index requests.
|
|
|
|
mutable llvm::StringMap<SymbolSlab> FuzzyFindCache;
|
|
|
|
mutable llvm::DenseMap<SymbolID, SymbolSlab> LookupCache;
|
|
|
|
// Returns None if the number of index requests has reached the limit.
|
|
|
|
llvm::Optional<const SymbolSlab *>
|
|
|
|
fuzzyFindCached(const FuzzyFindRequest &Req) const;
|
|
|
|
llvm::Optional<const SymbolSlab *> lookupCached(const SymbolID &ID) const;
|
2019-01-28 22:01:55 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|
|
|
|
|
|
|
|
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_INCLUDE_FIXER_H
|