blob: 9fa3d6955fc6f040ef2036edc0688033833ac621 [file] [log] [blame]
//===--- 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 "clang/Basic/SourceLocation.h"
#include "llvm/ADT/STLExtras.h"
namespace clang {
namespace clangd {
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);
auto Range = halfOpenToRange(
SM, CharSourceRange::getCharRange(Loc, MacroNameTok.getEndLoc()));
if (auto SID = getSymbolID(Name, MI, SM))
Out.MacroRefs[SID].push_back({Range, IsDefinition, InIfCondition});
else
Out.UnknownMacros.push_back({Range, 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<clangd::PragmaMark> &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<clangd::PragmaMark> &Out;
};
std::unique_ptr<PPCallbacks>
collectPragmaMarksCallback(const SourceManager &SM,
std::vector<PragmaMark> &Out) {
return std::make_unique<CollectPragmaMarks>(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