Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
clang-tools-extra/clangd/Preamble.cpp
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
#include <string> | #include <string> | ||||
#include <system_error> | #include <system_error> | ||||
#include <utility> | #include <utility> | ||||
#include <vector> | #include <vector> | ||||
namespace clang { | namespace clang { | ||||
namespace clangd { | namespace clangd { | ||||
namespace { | namespace { | ||||
constexpr llvm::StringLiteral PreamblePatchHeaderName = "__preamble_patch__.h"; | |||||
bool compileCommandsAreEqual(const tooling::CompileCommand &LHS, | bool compileCommandsAreEqual(const tooling::CompileCommand &LHS, | ||||
const tooling::CompileCommand &RHS) { | const tooling::CompileCommand &RHS) { | ||||
// We don't check for Output, it should not matter to clangd. | // We don't check for Output, it should not matter to clangd. | ||||
return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename && | return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename && | ||||
llvm::ArrayRef(LHS.CommandLine).equals(RHS.CommandLine); | llvm::ArrayRef(LHS.CommandLine).equals(RHS.CommandLine); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 311 Lines • ▼ Show 20 Lines | const char *spellingForIncDirective(tok::PPKeywordKind IncludeDirective) { | ||||
case tok::pp_include_next: | case tok::pp_include_next: | ||||
return "include_next"; | return "include_next"; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
llvm_unreachable("not an include directive"); | llvm_unreachable("not an include directive"); | ||||
} | } | ||||
// Checks whether \p FileName is a valid spelling of main file. | |||||
bool isMainFile(llvm::StringRef FileName, const SourceManager &SM) { | |||||
auto FE = SM.getFileManager().getFile(FileName); | |||||
return FE && *FE == SM.getFileEntryForID(SM.getMainFileID()); | |||||
} | |||||
// Accumulating wall time timer. Similar to llvm::Timer, but much cheaper, | // Accumulating wall time timer. Similar to llvm::Timer, but much cheaper, | ||||
// it only tracks wall time. | // it only tracks wall time. | ||||
// Since this is a generic timer, We may want to move this to support/ if we | // Since this is a generic timer, We may want to move this to support/ if we | ||||
// find a use case outside of FS time tracking. | // find a use case outside of FS time tracking. | ||||
class WallTimer { | class WallTimer { | ||||
public: | public: | ||||
WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {} | WallTimer() : TotalTime(std::chrono::steady_clock::duration::zero()) {} | ||||
// [Re-]Start the timer. | // [Re-]Start the timer. | ||||
▲ Show 20 Lines • Show All 257 Lines • ▼ Show 20 Lines | PreamblePatch PreamblePatch::create(llvm::StringRef FileName, | ||||
if ((PatchType == PatchType::MacroDirectives || !IncludesChanged) && | if ((PatchType == PatchType::MacroDirectives || !IncludesChanged) && | ||||
!DirectivesChanged) | !DirectivesChanged) | ||||
return PreamblePatch::unmodified(Baseline); | return PreamblePatch::unmodified(Baseline); | ||||
PreamblePatch PP; | PreamblePatch PP; | ||||
// This shouldn't coincide with any real file name. | // This shouldn't coincide with any real file name. | ||||
llvm::SmallString<128> PatchName; | llvm::SmallString<128> PatchName; | ||||
llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName), | llvm::sys::path::append(PatchName, llvm::sys::path::parent_path(FileName), | ||||
PreamblePatchHeaderName); | PreamblePatch::HeaderName); | ||||
PP.PatchFileName = PatchName.str().str(); | PP.PatchFileName = PatchName.str().str(); | ||||
PP.ModifiedBounds = ModifiedScan->Bounds; | PP.ModifiedBounds = ModifiedScan->Bounds; | ||||
llvm::raw_string_ostream Patch(PP.PatchContents); | llvm::raw_string_ostream Patch(PP.PatchContents); | ||||
// Set default filename for subsequent #line directives | // Set default filename for subsequent #line directives | ||||
Patch << "#line 0 \""; | Patch << "#line 0 \""; | ||||
// FileName part of a line directive is subject to backslash escaping, which | // FileName part of a line directive is subject to backslash escaping, which | ||||
// might lead to problems on windows especially. | // might lead to problems on windows especially. | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | |||||
PreamblePatch PreamblePatch::unmodified(const PreambleData &Preamble) { | PreamblePatch PreamblePatch::unmodified(const PreambleData &Preamble) { | ||||
PreamblePatch PP; | PreamblePatch PP; | ||||
PP.PreambleIncludes = Preamble.Includes.MainFileIncludes; | PP.PreambleIncludes = Preamble.Includes.MainFileIncludes; | ||||
PP.ModifiedBounds = Preamble.Preamble.getBounds(); | PP.ModifiedBounds = Preamble.Preamble.getBounds(); | ||||
return PP; | return PP; | ||||
} | } | ||||
SourceLocation translatePreamblePatchLocation(SourceLocation Loc, | |||||
const SourceManager &SM) { | |||||
auto DefFile = SM.getFileID(Loc); | |||||
if (auto FE = SM.getFileEntryRefForID(DefFile)) { | |||||
auto IncludeLoc = SM.getIncludeLoc(DefFile); | |||||
// Preamble patch is included inside the builtin file. | |||||
if (IncludeLoc.isValid() && SM.isWrittenInBuiltinFile(IncludeLoc) && | |||||
FE->getName().endswith(PreamblePatchHeaderName)) { | |||||
auto Presumed = SM.getPresumedLoc(Loc); | |||||
// Check that line directive is pointing at main file. | |||||
if (Presumed.isValid() && Presumed.getFileID().isInvalid() && | |||||
isMainFile(Presumed.getFilename(), SM)) { | |||||
Loc = SM.translateLineCol(SM.getMainFileID(), Presumed.getLine(), | |||||
Presumed.getColumn()); | |||||
} | |||||
} | |||||
} | |||||
return Loc; | |||||
} | |||||
bool PreamblePatch::preserveDiagnostics() const { | bool PreamblePatch::preserveDiagnostics() const { | ||||
return PatchContents.empty() || | return PatchContents.empty() || | ||||
Config::current().Diagnostics.AllowStalePreamble; | Config::current().Diagnostics.AllowStalePreamble; | ||||
} | } | ||||
} // namespace clangd | } // namespace clangd | ||||
} // namespace clang | } // namespace clang |