155 lines · cpp
1//===--- CollectMacros.cpp ---------------------------------------*- 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-exception6//7//===----------------------------------------------------------------------===//8 9#include "CollectMacros.h"10#include "AST.h"11#include "Protocol.h"12#include "SourceCode.h"13#include "clang/Basic/SourceLocation.h"14#include "clang/Tooling/Syntax/Tokens.h"15#include "llvm/ADT/STLExtras.h"16#include <cstddef>17 18namespace clang {19namespace clangd {20 21CharSourceRange MacroOccurrence::toSourceRange(const SourceManager &SM) const {22 auto MainFile = SM.getMainFileID();23 return syntax::FileRange(MainFile, StartOffset, EndOffset).toCharRange(SM);24}25 26Range MacroOccurrence::toRange(const SourceManager &SM) const {27 return halfOpenToRange(SM, toSourceRange(SM));28}29 30void CollectMainFileMacros::add(const Token &MacroNameTok, const MacroInfo *MI,31 bool IsDefinition, bool InIfCondition) {32 if (!InMainFile)33 return;34 auto Loc = MacroNameTok.getLocation();35 if (Loc.isInvalid() || Loc.isMacroID())36 return;37 38 assert(isInsideMainFile(Loc, SM));39 auto Name = MacroNameTok.getIdentifierInfo()->getName();40 Out.Names.insert(Name);41 size_t Start = SM.getFileOffset(Loc);42 size_t End = SM.getFileOffset(MacroNameTok.getEndLoc());43 if (auto SID = getSymbolID(Name, MI, SM))44 Out.MacroRefs[SID].push_back({Start, End, IsDefinition, InIfCondition});45 else46 Out.UnknownMacros.push_back({Start, End, IsDefinition, InIfCondition});47}48 49void CollectMainFileMacros::FileChanged(SourceLocation Loc, FileChangeReason,50 SrcMgr::CharacteristicKind, FileID) {51 InMainFile = isInsideMainFile(Loc, SM);52}53 54void CollectMainFileMacros::MacroExpands(const Token &MacroName,55 const MacroDefinition &MD,56 SourceRange Range,57 const MacroArgs *Args) {58 add(MacroName, MD.getMacroInfo());59}60 61void CollectMainFileMacros::MacroUndefined(const clang::Token &MacroName,62 const clang::MacroDefinition &MD,63 const clang::MacroDirective *Undef) {64 add(MacroName, MD.getMacroInfo());65}66 67void CollectMainFileMacros::Ifdef(SourceLocation Loc, const Token &MacroName,68 const MacroDefinition &MD) {69 add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false,70 /*InConditionalDirective=*/true);71}72 73void CollectMainFileMacros::Ifndef(SourceLocation Loc, const Token &MacroName,74 const MacroDefinition &MD) {75 add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false,76 /*InConditionalDirective=*/true);77}78 79void CollectMainFileMacros::Elifdef(SourceLocation Loc, const Token &MacroName,80 const MacroDefinition &MD) {81 add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false,82 /*InConditionalDirective=*/true);83}84 85void CollectMainFileMacros::Elifndef(SourceLocation Loc, const Token &MacroName,86 const MacroDefinition &MD) {87 add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false,88 /*InConditionalDirective=*/true);89}90 91void CollectMainFileMacros::Defined(const Token &MacroName,92 const MacroDefinition &MD,93 SourceRange Range) {94 add(MacroName, MD.getMacroInfo(), /*IsDefinition=*/false,95 /*InConditionalDirective=*/true);96}97 98void CollectMainFileMacros::SourceRangeSkipped(SourceRange R,99 SourceLocation EndifLoc) {100 if (!InMainFile)101 return;102 Position Begin = sourceLocToPosition(SM, R.getBegin());103 Position End = sourceLocToPosition(SM, R.getEnd());104 Out.SkippedRanges.push_back(Range{Begin, End});105}106 107class CollectPragmaMarks : public PPCallbacks {108public:109 explicit CollectPragmaMarks(const SourceManager &SM,110 std::vector<clangd::PragmaMark> &Out)111 : SM(SM), Out(Out) {}112 113 void PragmaMark(SourceLocation Loc, StringRef Trivia) override {114 if (isInsideMainFile(Loc, SM)) {115 // FIXME: This range should just cover `XX` in `#pragma mark XX` and116 // `- XX` in `#pragma mark - XX`.117 Position Start = sourceLocToPosition(SM, Loc);118 Position End = {Start.line + 1, 0};119 Out.emplace_back(clangd::PragmaMark{{Start, End}, Trivia.str()});120 }121 }122 123private:124 const SourceManager &SM;125 std::vector<clangd::PragmaMark> &Out;126};127 128std::unique_ptr<PPCallbacks>129collectPragmaMarksCallback(const SourceManager &SM,130 std::vector<PragmaMark> &Out) {131 return std::make_unique<CollectPragmaMarks>(SM, Out);132}133 134void CollectMainFileMacros::MacroDefined(const Token &MacroName,135 const MacroDirective *MD) {136 137 if (!InMainFile)138 return;139 const auto *MI = MD->getMacroInfo();140 add(MacroName, MD->getMacroInfo(), true);141 if (MI)142 for (const auto &Tok : MI->tokens()) {143 auto *II = Tok.getIdentifierInfo();144 // Could this token be a reference to a macro? (Not param to this macro).145 if (!II || !II->hadMacroDefinition() ||146 llvm::is_contained(MI->params(), II))147 continue;148 if (const MacroInfo *MI = PP.getMacroInfo(II))149 add(Tok, MI);150 }151}152 153} // namespace clangd154} // namespace clang155