//===--- PotentialMacroExpansions.h -----------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines a structure (\c PotentialMacroExpansions) to track // potential macro expansions within a given context. // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_POTENTIAL_MACRO_EXPANSIONS_H #define SWIFT_AST_POTENTIAL_MACRO_EXPANSIONS_H #include "swift/AST/Identifier.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallPtrSet.h" namespace swift { /// Describes the potential macro expansions within a given type or /// extension context. class PotentialMacroExpansions { enum { /// Whether there are any expanded macros. AnyExpandedMacros = 0x01, /// Whether any of the expanded macros introduces arbitrary names. IntroducesArbitraryNames = 0x02, }; using NameSet = llvm::SmallPtrSet; /// Storage for the set of potential macro expansions. llvm::PointerIntPair Storage; /// Retrieve a pointer to the name set if there is one. const NameSet *getIntroducedNamesIfAvailable() const { return Storage.getPointer(); } /// Get or create a nam NameSet &getOrCreateIntroducedNames() { if (auto nameSet = Storage.getPointer()) return *nameSet; // Allocate a new set of introduced names. auto nameSet = new NameSet(); Storage.setPointer(nameSet); return *nameSet; } public: PotentialMacroExpansions() : Storage() { } PotentialMacroExpansions(const PotentialMacroExpansions &other) : Storage(nullptr, other.Storage.getInt()) { if (auto otherNameSet = other.getIntroducedNamesIfAvailable()) { Storage.setPointer(new NameSet(*otherNameSet)); } } PotentialMacroExpansions(PotentialMacroExpansions &&other) : Storage(other.Storage) { other.Storage.setPointer(nullptr); } PotentialMacroExpansions &operator=(const PotentialMacroExpansions &other) { PotentialMacroExpansions tmp(other); swap(tmp, *this); return *this; } PotentialMacroExpansions &operator=(PotentialMacroExpansions &&other) { if (&other != this) { Storage = other.Storage; other.Storage.setPointer(nullptr); } return *this; } ~PotentialMacroExpansions() { delete getIntroducedNamesIfAvailable(); } /// Whether there are any expanded macros in this context. explicit operator bool() const { return hasAnyExpandedMacro(); } /// Whether there are any expanded macros in this context. bool hasAnyExpandedMacro() const { return Storage.getInt() & AnyExpandedMacros; } /// Note that we have expanded a macro. void noteExpandedMacro() { Storage.setInt(Storage.getInt() | AnyExpandedMacros); } /// Whether any expanded macro introduces arbitrary names. bool introducesArbitraryNames() const { return Storage.getInt() & IntroducesArbitraryNames; } /// Note that a macro expanded here introduced arbitrary names. void noteIntroducesArbitraryNames() { Storage.setInt(Storage.getInt() | IntroducesArbitraryNames); } /// Add a new introduced macro name. void addIntroducedMacroName(DeclName name) { getOrCreateIntroducedNames().insert(name.getBaseName()); } /// Determine whether one should expand any macros in this context because /// they could introduce a declaration with the given name. bool shouldExpandForName(DeclName name) const { // If any macro produces arbitraty names, we need to expand it. if (introducesArbitraryNames()) return true; auto introducedNames = getIntroducedNamesIfAvailable(); if (!introducedNames) return false; return introducedNames->count(name.getBaseName()); } friend bool operator==(const PotentialMacroExpansions &lhs, const PotentialMacroExpansions &rhs) { // Check has-any-expanded-macro and introduces-arbitrary-names together. if (lhs.Storage.getInt() != rhs.Storage.getInt()) return false; // If they introduced arbitrary names, ignore the name sets... they are // the same. if (lhs.introducesArbitraryNames()) return true; // Both expanded macros and did not introduce arbitrary names, so we need // to check the actual names. auto lhsIntroducedNames = lhs.getIntroducedNamesIfAvailable(); auto rhsIntroducedNames = rhs.getIntroducedNamesIfAvailable(); auto lhsIntroducedNamesCount = lhsIntroducedNames ? lhsIntroducedNames->size() : 0; auto rhsIntroducedNamesCount = rhsIntroducedNames ? rhsIntroducedNames->size() : 0; if (lhsIntroducedNamesCount != rhsIntroducedNamesCount) return false; // Check whether both are empty. if (lhsIntroducedNamesCount == 0) return true; // Make sure all of the names of one are in the other. for (auto lhsName : *lhsIntroducedNames) { if (rhsIntroducedNames->count(lhsName) == 0) return false; } return true; } friend bool operator!=(const PotentialMacroExpansions &lhs, const PotentialMacroExpansions &rhs) { return !(lhs == rhs); } friend void swap( PotentialMacroExpansions &lhs, PotentialMacroExpansions &rhs) { auto tmpStorage = lhs.Storage; lhs.Storage = rhs.Storage; rhs.Storage = tmpStorage; } }; } #endif // SWIFT_AST_POTENTIAL_MACRO_EXPANSIONS_H