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