llvm-project
266 строк · 9.0 Кб
1//===- MacroInfo.cpp - Information about #defined identifiers -------------===//
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// This file implements the MacroInfo interface.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/Lex/MacroInfo.h"14#include "clang/Basic/IdentifierTable.h"15#include "clang/Basic/LLVM.h"16#include "clang/Basic/SourceLocation.h"17#include "clang/Basic/SourceManager.h"18#include "clang/Basic/TokenKinds.h"19#include "clang/Lex/Preprocessor.h"20#include "clang/Lex/Token.h"21#include "llvm/ADT/StringRef.h"22#include "llvm/Support/Casting.h"23#include "llvm/Support/Compiler.h"24#include "llvm/Support/raw_ostream.h"25#include <cassert>26#include <optional>27#include <utility>28
29using namespace clang;30
31namespace {32
33// MacroInfo is expected to take 40 bytes on platforms with an 8 byte pointer
34// and 4 byte SourceLocation.
35template <int> class MacroInfoSizeChecker {36public:37[[maybe_unused]] constexpr static bool AsExpected = true;38};39template <> class MacroInfoSizeChecker<8> {40public:41[[maybe_unused]] constexpr static bool AsExpected =42sizeof(MacroInfo) == (32 + sizeof(SourceLocation) * 2);43};44
45static_assert(MacroInfoSizeChecker<sizeof(void *)>::AsExpected,46"Unexpected size of MacroInfo");47
48} // end namespace49
50MacroInfo::MacroInfo(SourceLocation DefLoc)51: Location(DefLoc), IsDefinitionLengthCached(false), IsFunctionLike(false),52IsC99Varargs(false), IsGNUVarargs(false), IsBuiltinMacro(false),53HasCommaPasting(false), IsDisabled(false), IsUsed(false),54IsAllowRedefinitionsWithoutWarning(false), IsWarnIfUnused(false),55UsedForHeaderGuard(false) {}56
57unsigned MacroInfo::getDefinitionLengthSlow(const SourceManager &SM) const {58assert(!IsDefinitionLengthCached);59IsDefinitionLengthCached = true;60
61ArrayRef<Token> ReplacementTokens = tokens();62if (ReplacementTokens.empty())63return (DefinitionLength = 0);64
65const Token &firstToken = ReplacementTokens.front();66const Token &lastToken = ReplacementTokens.back();67SourceLocation macroStart = firstToken.getLocation();68SourceLocation macroEnd = lastToken.getLocation();69assert(macroStart.isValid() && macroEnd.isValid());70assert((macroStart.isFileID() || firstToken.is(tok::comment)) &&71"Macro defined in macro?");72assert((macroEnd.isFileID() || lastToken.is(tok::comment)) &&73"Macro defined in macro?");74std::pair<FileID, unsigned>75startInfo = SM.getDecomposedExpansionLoc(macroStart);76std::pair<FileID, unsigned>77endInfo = SM.getDecomposedExpansionLoc(macroEnd);78assert(startInfo.first == endInfo.first &&79"Macro definition spanning multiple FileIDs ?");80assert(startInfo.second <= endInfo.second);81DefinitionLength = endInfo.second - startInfo.second;82DefinitionLength += lastToken.getLength();83
84return DefinitionLength;85}
86
87/// Return true if the specified macro definition is equal to
88/// this macro in spelling, arguments, and whitespace.
89///
90/// \param Syntactically if true, the macro definitions can be identical even
91/// if they use different identifiers for the function macro parameters.
92/// Otherwise the comparison is lexical and this implements the rules in
93/// C99 6.10.3.
94bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,95bool Syntactically) const {96bool Lexically = !Syntactically;97
98// Check # tokens in replacement, number of args, and various flags all match.99if (getNumTokens() != Other.getNumTokens() ||100getNumParams() != Other.getNumParams() ||101isFunctionLike() != Other.isFunctionLike() ||102isC99Varargs() != Other.isC99Varargs() ||103isGNUVarargs() != Other.isGNUVarargs())104return false;105
106if (Lexically) {107// Check arguments.108for (param_iterator I = param_begin(), OI = Other.param_begin(),109E = param_end();110I != E; ++I, ++OI)111if (*I != *OI) return false;112}113
114// Check all the tokens.115for (unsigned i = 0; i != NumReplacementTokens; ++i) {116const Token &A = ReplacementTokens[i];117const Token &B = Other.ReplacementTokens[i];118if (A.getKind() != B.getKind())119return false;120
121// If this isn't the first token, check that the whitespace and122// start-of-line characteristics match.123if (i != 0 &&124(A.isAtStartOfLine() != B.isAtStartOfLine() ||125A.hasLeadingSpace() != B.hasLeadingSpace()))126return false;127
128// If this is an identifier, it is easy.129if (A.getIdentifierInfo() || B.getIdentifierInfo()) {130if (A.getIdentifierInfo() == B.getIdentifierInfo())131continue;132if (Lexically)133return false;134// With syntactic equivalence the parameter names can be different as long135// as they are used in the same place.136int AArgNum = getParameterNum(A.getIdentifierInfo());137if (AArgNum == -1)138return false;139if (AArgNum != Other.getParameterNum(B.getIdentifierInfo()))140return false;141continue;142}143
144// Otherwise, check the spelling.145if (PP.getSpelling(A) != PP.getSpelling(B))146return false;147}148
149return true;150}
151
152LLVM_DUMP_METHOD void MacroInfo::dump() const {153llvm::raw_ostream &Out = llvm::errs();154
155// FIXME: Dump locations.156Out << "MacroInfo " << this;157if (IsBuiltinMacro) Out << " builtin";158if (IsDisabled) Out << " disabled";159if (IsUsed) Out << " used";160if (IsAllowRedefinitionsWithoutWarning)161Out << " allow_redefinitions_without_warning";162if (IsWarnIfUnused) Out << " warn_if_unused";163if (UsedForHeaderGuard) Out << " header_guard";164
165Out << "\n #define <macro>";166if (IsFunctionLike) {167Out << "(";168for (unsigned I = 0; I != NumParameters; ++I) {169if (I) Out << ", ";170Out << ParameterList[I]->getName();171}172if (IsC99Varargs || IsGNUVarargs) {173if (NumParameters && IsC99Varargs) Out << ", ";174Out << "...";175}176Out << ")";177}178
179bool First = true;180for (const Token &Tok : tokens()) {181// Leading space is semantically meaningful in a macro definition,182// so preserve it in the dump output.183if (First || Tok.hasLeadingSpace())184Out << " ";185First = false;186
187if (const char *Punc = tok::getPunctuatorSpelling(Tok.getKind()))188Out << Punc;189else if (Tok.isLiteral() && Tok.getLiteralData())190Out << StringRef(Tok.getLiteralData(), Tok.getLength());191else if (auto *II = Tok.getIdentifierInfo())192Out << II->getName();193else194Out << Tok.getName();195}196}
197
198MacroDirective::DefInfo MacroDirective::getDefinition() {199MacroDirective *MD = this;200SourceLocation UndefLoc;201std::optional<bool> isPublic;202for (; MD; MD = MD->getPrevious()) {203if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD))204return DefInfo(DefMD, UndefLoc, !isPublic || *isPublic);205
206if (UndefMacroDirective *UndefMD = dyn_cast<UndefMacroDirective>(MD)) {207UndefLoc = UndefMD->getLocation();208continue;209}210
211VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD);212if (!isPublic)213isPublic = VisMD->isPublic();214}215
216return DefInfo(nullptr, UndefLoc, !isPublic || *isPublic);217}
218
219const MacroDirective::DefInfo220MacroDirective::findDirectiveAtLoc(SourceLocation L,221const SourceManager &SM) const {222assert(L.isValid() && "SourceLocation is invalid.");223for (DefInfo Def = getDefinition(); Def; Def = Def.getPreviousDefinition()) {224if (Def.getLocation().isInvalid() || // For macros defined on the command line.225SM.isBeforeInTranslationUnit(Def.getLocation(), L))226return (!Def.isUndefined() ||227SM.isBeforeInTranslationUnit(L, Def.getUndefLocation()))228? Def : DefInfo();229}230return DefInfo();231}
232
233LLVM_DUMP_METHOD void MacroDirective::dump() const {234llvm::raw_ostream &Out = llvm::errs();235
236switch (getKind()) {237case MD_Define: Out << "DefMacroDirective"; break;238case MD_Undefine: Out << "UndefMacroDirective"; break;239case MD_Visibility: Out << "VisibilityMacroDirective"; break;240}241Out << " " << this;242// FIXME: Dump SourceLocation.243if (auto *Prev = getPrevious())244Out << " prev " << Prev;245if (IsFromPCH) Out << " from_pch";246
247if (isa<VisibilityMacroDirective>(this))248Out << (IsPublic ? " public" : " private");249
250if (auto *DMD = dyn_cast<DefMacroDirective>(this)) {251if (auto *Info = DMD->getInfo()) {252Out << "\n ";253Info->dump();254}255}256Out << "\n";257}
258
259ModuleMacro *ModuleMacro::create(Preprocessor &PP, Module *OwningModule,260const IdentifierInfo *II, MacroInfo *Macro,261ArrayRef<ModuleMacro *> Overrides) {262void *Mem = PP.getPreprocessorAllocator().Allocate(263sizeof(ModuleMacro) + sizeof(ModuleMacro *) * Overrides.size(),264alignof(ModuleMacro));265return new (Mem) ModuleMacro(OwningModule, II, Macro, Overrides);266}
267