1 /****************************************************************************** 2 * 3 * Copyright (C) 1997-2020 by Dimitri van Heesch. 4 * 5 * Permission to use, copy, modify, and distribute this software and its 6 * documentation under the terms of the GNU General Public License is hereby 7 * granted. No representations are made about the suitability of this software 8 * for any purpose. It is provided "as is" without express or implied warranty. 9 * See the GNU General Public License for more details. 10 * 11 * Documents produced by Doxygen are derivative works derived from the 12 * input used in their production; they are not affected by this license. 13 * 14 */ 15 16 #ifndef SCOPEDTYPEVARIANT_H 17 #define SCOPEDTYPEVARIANT_H 18 19 #include <utility> 20 #include <vector> 21 22 #include "qcstring.h" 23 #include "definition.h" 24 25 //! Class representing a local class definition found while 26 //! generating syntax highlighted code. 27 class LocalDef 28 { 29 public: insertBaseClass(const QCString & name)30 void insertBaseClass(const QCString &name) { m_baseClasses.push_back(name); } baseClasses()31 std::vector<QCString> baseClasses() const { return m_baseClasses; } 32 private: 33 std::vector<QCString> m_baseClasses; 34 }; 35 36 //----------------------------------------------------------------------------- 37 38 /*! Variant class for a scoped type. 39 * 40 * Variants: 41 * - Dummy: a type used for hiding a global type. 42 * - Local: a locally defined type (e.g. found inside a function) 43 * - Global: a globally defined type (processed by doxygen in an earlier pass). 44 */ 45 class ScopedTypeVariant 46 { 47 public: 48 //! possible variant types 49 enum Variant 50 { 51 Global, 52 Local, 53 Dummy 54 }; 55 //! default constructor for creating a variant of type Dummy ScopedTypeVariant()56 ScopedTypeVariant() : m_variant(Dummy) 57 { 58 m_u.globalDef = 0; 59 } 60 //! constructor for creating a variant of type Global ScopedTypeVariant(const Definition * d)61 explicit ScopedTypeVariant(const Definition *d) 62 { 63 if (d) 64 { 65 m_name = d->name(); 66 m_variant = Global; 67 m_u.globalDef = d; 68 } 69 else 70 { 71 m_variant = Dummy; 72 m_u.globalDef = 0; 73 } 74 } 75 //! constructor for creating a variant of type Local ScopedTypeVariant(const QCString & name)76 explicit ScopedTypeVariant(const QCString &name) 77 { 78 m_name = name; 79 m_variant = Local; 80 m_u.localDef = new LocalDef; 81 } 82 //! copy constructor ScopedTypeVariant(const ScopedTypeVariant & stv)83 ScopedTypeVariant(const ScopedTypeVariant &stv) 84 { 85 m_variant = stv.m_variant; 86 m_name = stv.m_name; 87 if (m_variant==Local) 88 { 89 m_u.localDef = new LocalDef(*stv.m_u.localDef); 90 } 91 else if (m_variant==Global) 92 { 93 m_u.globalDef = stv.m_u.globalDef; 94 } 95 } 96 //! move constructor ScopedTypeVariant(ScopedTypeVariant && stv)97 ScopedTypeVariant(ScopedTypeVariant &&stv) noexcept : ScopedTypeVariant() 98 { 99 swap(*this,stv); 100 } 101 //! assignment operator 102 ScopedTypeVariant &operator=(ScopedTypeVariant stv) 103 { 104 swap(*this,stv); 105 return *this; 106 } 107 //! destructor ~ScopedTypeVariant()108 ~ScopedTypeVariant() 109 { 110 if (m_variant==Local) 111 { 112 delete m_u.localDef; 113 } 114 } 115 //! swap function swap(ScopedTypeVariant & first,ScopedTypeVariant & second)116 friend void swap(ScopedTypeVariant &first,ScopedTypeVariant &second) 117 { 118 using std::swap; // enable ADL 119 swap(first.m_variant,second.m_variant); 120 swap(first.m_name,second.m_name); 121 swap(first.m_u.globalDef,second.m_u.globalDef); 122 } 123 //! Turn the variant into a Global type setGlobal(const Definition * def)124 void setGlobal(const Definition *def) 125 { 126 if (m_variant==Local) 127 { 128 delete m_u.localDef; 129 } 130 m_variant = Global; 131 m_name = def->name(); 132 m_u.globalDef = def; 133 } 134 //! Turn the variant into a Local type setLocal(const QCString & name)135 LocalDef *setLocal(const QCString &name) 136 { 137 if (m_variant==Local) 138 { 139 delete m_u.localDef; 140 } 141 m_variant = Local; 142 m_name = name; 143 m_u.localDef = new LocalDef; 144 return m_u.localDef; 145 } 146 //! Turn the variant into a Dummy type setDummy()147 void setDummy() 148 { 149 if (m_variant==Local) 150 { 151 delete m_u.localDef; 152 } 153 m_variant = Dummy; 154 m_name = ""; 155 m_u.localDef=0; 156 } type()157 Variant type() const { return m_variant; } name()158 QCString name() const { return m_name; } localDef()159 LocalDef *localDef() const { return m_variant==Local ? m_u.localDef : 0; } globalDef()160 const Definition *globalDef() const { return m_variant==Global ? m_u.globalDef : 0; } 161 162 private: 163 Variant m_variant; 164 QCString m_name; 165 union 166 { 167 const Definition *globalDef; 168 LocalDef *localDef; 169 } m_u; 170 }; 171 172 //----------------------------------------------------------------------------- 173 174 /*! Represents a stack of variable to class mappings as found in the 175 * code. Each scope is enclosed in pushScope() and popScope() calls. 176 * Variables are added by calling addVariables() and one can search 177 * for variable using findVariable(). 178 */ 179 class VariableContext 180 { 181 public: 182 using Scope = std::unordered_map<std::string,ScopedTypeVariant>; 183 pushScope()184 void pushScope() 185 { 186 m_scopes.push_back(Scope()); 187 } popScope()188 void popScope() 189 { 190 if (!m_scopes.empty()) 191 { 192 m_scopes.pop_back(); 193 } 194 } clear()195 void clear() 196 { 197 m_scopes.clear(); 198 m_globalScope.clear(); 199 } clearExceptGlobal()200 void clearExceptGlobal() 201 { 202 m_scopes.clear(); 203 } addVariable(const QCString & name,ScopedTypeVariant stv)204 void addVariable(const QCString &name,ScopedTypeVariant stv) 205 { 206 Scope *scope = m_scopes.empty() ? &m_globalScope : &m_scopes.back(); 207 scope->emplace(std::make_pair(name.str(),std::move(stv))); // add it to a list 208 } findVariable(const QCString & name)209 const ScopedTypeVariant *findVariable(const QCString &name) 210 { 211 const ScopedTypeVariant *result = 0; 212 if (name.isEmpty()) return result; 213 214 // search from inner to outer scope 215 auto it = std::rbegin(m_scopes); 216 while (it != std::rend(m_scopes)) 217 { 218 auto it2 = it->find(name.str()); 219 if (it2 != std::end(*it)) 220 { 221 result = &it2->second; 222 return result; 223 } 224 ++it; 225 } 226 // nothing found -> also try the global scope 227 auto it2 = m_globalScope.find(name.str()); 228 if (it2 != m_globalScope.end()) 229 { 230 result = &it2->second; 231 } 232 return result; 233 } atGlobalScope()234 bool atGlobalScope() const { return m_scopes.empty(); } 235 236 private: 237 Scope m_globalScope; 238 std::vector<Scope> m_scopes; 239 }; 240 241 //----------------------------------------------------------------------------- 242 243 /** Represents the call context */ 244 class CallContext 245 { 246 public: 247 struct Ctx 248 { CtxCtx249 Ctx(const QCString &name_,const QCString &type_) : name(name_), type(type_) {} 250 QCString name; 251 QCString type; 252 ScopedTypeVariant stv; 253 }; 254 CallContext()255 CallContext() 256 { 257 clear(); 258 } setScope(const ScopedTypeVariant & stv)259 void setScope(const ScopedTypeVariant &stv) 260 { 261 Ctx &ctx = m_stvList.back(); 262 ctx.stv=std::move(stv); 263 } pushScope(const QCString & name_,const QCString & type_)264 void pushScope(const QCString &name_,const QCString &type_) 265 { 266 m_stvList.push_back(Ctx(name_,type_)); 267 } popScope(QCString & name_,QCString & type_)268 void popScope(QCString &name_,QCString &type_) 269 { 270 if (m_stvList.size()>1) 271 { 272 const Ctx &ctx = m_stvList.back(); 273 name_ = ctx.name; 274 type_ = ctx.type; 275 m_stvList.pop_back(); 276 } 277 } clear()278 void clear() 279 { 280 m_stvList.clear(); 281 m_stvList.push_back(Ctx(QCString(),QCString())); 282 } getScope()283 const ScopedTypeVariant getScope() const 284 { 285 return m_stvList.back().stv; 286 } 287 288 private: 289 std::vector<Ctx> m_stvList; 290 }; 291 292 293 #endif 294