//===--- CollectMacros.cpp ---------------------------------------*- 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 // //===----------------------------------------------------------------------===// #include "CollectMacros.h" #include "AST.h" #include "Protocol.h" #include "SourceCode.h" #include "clang/Basic/SourceLocation.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/STLExtras.h" #include namespace clang { namespace clangd { Range MacroOccurrence::toRange(const SourceManager &SM) const { auto MainFile = SM.getMainFileID(); return halfOpenToRange( SM, syntax::FileRange(MainFile, StartOffset, EndOffset).toCharRange(SM)); } void CollectMainFileMacros::add(const Token &MacroNameTok, const MacroInfo *MI, bool IsDefinition, bool InIfCondition) { if (!InMainFile) return; auto Loc = MacroNameTok.getLocation(); if (Loc.isInvalid() || Loc.isMacroID()) return; auto Name = MacroNameTok.getIdentifierInfo()->getName(); Out.Names.insert(Name); size_t Start = SM.getFileOffset(Loc); size_t End = SM.getFileOffset(MacroNameTok.getEndLoc()); if (auto SID = getSymbolID(Name, MI, SM)) Out.MacroRefs[SID].push_back({Start, End, IsDefinition, InIfCondition}); else Out.UnknownMacros.push_back({Start, End, IsDefinition, InIfCondition}); } void CollectMainFileMacros::FileChanged(SourceLocation Loc, FileChangeReason, SrcMgr::CharacteristicKind, FileID) { InMainFile = isInsideMainFile(Loc, SM); } void CollectMainFileMacros::MacroExpands(const Token &MacroName, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) { add(MacroName, MD.getMacroInfo()); } void CollectMainFileMacros::MacroUndefined(const clang::Token &MacroName, const clang::MacroDefinition &MD, const clang::MacroDirective *Undef) { add(MacroName, MD.getMacroInfo()); } void CollectMainFileMacros::Ifdef(SourceLocation Loc, const Token &MacroName, const MacroDefinition &MD) { add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false, /*InConditionalDirective=*/true); } void CollectMainFileMacros::Ifndef(SourceLocation Loc, const Token &MacroName, const MacroDefinition &MD) { add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false, /*InConditionalDirective=*/true); } void CollectMainFileMacros::Elifdef(SourceLocation Loc, const Token &MacroName, const MacroDefinition &MD) { add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false, /*InConditionalDirective=*/true); } void CollectMainFileMacros::Elifndef(SourceLocation Loc, const Token &MacroName, const MacroDefinition &MD) { add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false, /*InConditionalDirective=*/true); } void CollectMainFileMacros::Defined(const Token &MacroName, const MacroDefinition &MD, SourceRange Range) { add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false, /*InConditionalDirective=*/true); } void CollectMainFileMacros::SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) { if (!InMainFile) return; Position Begin = sourceLocToPosition(SM, R.getBegin()); Position End = sourceLocToPosition(SM, R.getEnd()); Out.SkippedRanges.push_back(Range{Begin, End}); } class CollectPragmaMarks : public PPCallbacks { public: explicit CollectPragmaMarks(const SourceManager &SM, std::vector &Out) : SM(SM), Out(Out) {} void PragmaMark(SourceLocation Loc, StringRef Trivia) override { if (isInsideMainFile(Loc, SM)) { // FIXME: This range should just cover `XX` in `#pragma mark XX` and // `- XX` in `#pragma mark - XX`. Position Start = sourceLocToPosition(SM, Loc); Position End = {Start.line + 1, 0}; Out.emplace_back(clangd::PragmaMark{{Start, End}, Trivia.str()}); } } private: const SourceManager &SM; std::vector &Out; }; std::unique_ptr collectPragmaMarksCallback(const SourceManager &SM, std::vector &Out) { return std::make_unique(SM, Out); } void CollectMainFileMacros::MacroDefined(const Token &MacroName, const MacroDirective *MD) { if (!InMainFile) return; const auto *MI = MD->getMacroInfo(); add(MacroName, MD->getMacroInfo(), true); if (MI) for (const auto &Tok : MI->tokens()) { auto *II = Tok.getIdentifierInfo(); // Could this token be a reference to a macro? (Not param to this macro). if (!II || !II->hadMacroDefinition() || llvm::is_contained(MI->params(), II)) continue; if (const MacroInfo *MI = PP.getMacroInfo(II)) add(Tok, MI); } } } // namespace clangd } // namespace clang