#include "CppBase.h" namespace Upp { #define LLOG(x) // DLOG(x) #define LTIMING(x) // RTIMING(x) bool DoQualify(ScopeInfo& nf, const String& type, const String& usings, String& qt); bool Qualify0(ScopeInfo& nf, const String& type, const String& usings, String& qt) { // Qualify single type based on scoping information const Vector& nd = nf.GetScopes(usings); if(nd.GetCount()) { LTIMING("First test"); qt = nd[0] + type; if(nf.base.Find(qt) >= 0) return true; } if(nf.GetScope() >= 0) { int q = type.ReverseFind(':'); if(q > 0) { LTIMING("Qualifying qualification"); ScopeInfo hnf(nf); hnf.NoBases(); String qn; String qs = type.Mid(0, q - 1); if(IsDigit(*qs)) { qt = type; return true; } if(DoQualify(hnf, qs, usings, qn)) { String tp = type.Mid(q + 1); if(nf.base.Find(qn) >= 0) { qt = qn + "::" + tp; return true; } int scopei = nf.base.Find(qn); if(scopei >= 0) { ScopeInfo nnf(nf.base, scopei); const Vector& bs = nnf.GetBases(); for(int i = 0; i < bs.GetCount(); i++) { qt = bs[i] + tp; if(nf.base.Find(qt) >= 0) return true; } } } if(nf.base.Find(qs) >= 0) { qt = qs; return true; } qt = type; if(nf.base.Find(qt) >= 0) // e.g. std::string return true; qt = type.Mid(q + 1); return true; } else { LTIMING("Bases"); const Vector& bs = nf.GetBases(); for(int i = 0; i < bs.GetCount(); i++) { qt = bs[i] + type; if(nf.base.Find(qt) >= 0) return true; } } } if(type[0] != ':') { LTIMING("Testing scopes"); for(int i = 1; i < nd.GetCount(); i++) { qt = nd[i] + type; if(nf.base.Find(qt) >= 0) return true; } } int q = type.Find(':'); if(q < 0) return false; return Qualify0(nf, type.Mid(q + 1), usings, qt); } bool DoQualify(ScopeInfo& nf, const String& type, const String& usings, String& qt) { LTIMING("Qualify"); int q = nf.cache.Find(type); if(q >= 0) { qt = nf.cache[q]; return true; } LTIMING("Qualify0"); if(!Qualify0(nf, type, usings, qt)) return false; nf.cache.Add(type, qt); return true; } String DoQualify(ScopeInfo& nf, const String& type, const String& usings) { String qt; return DoQualify(nf, type, usings, qt) ? qt : type; } static String s_int("int"); static String s_void("void"); static String s_double("double"); static String s_char("char"); static String s_float("float"); static String s_long("long"); static String s_const("const"); static String s_struct("struct"); static String s_class("class"); static String s_unsigned("unsigned"); inline void Qualify(String& r, ScopeInfo& nf, const char *b, const char *s, const String& usings) { String type(b, s); if(type.GetCount() == 0 || type == s_const || type == s_int || type == s_double || type == s_char || type == s_long || type == s_unsigned || type == s_struct || type == s_class || type == s_float) { r << type; return; } r << DoQualify(nf, type, usings); } String QualifyIds(ScopeInfo& nf, const String& k, const String& usings, bool all) { LTIMING("QualifyIds"); String r; const char *s = k; Vector empty; while(*s) { int c = *s; if(c == ':') { const char *b = s++; while(*s == ':' || iscid(*s)) s++; /* if(all) { if(iscid(*r.Last())) r << ' '; ScopeInfo nnf(nf.GetScope(), nf.base); Qualify(r, nnf, b, s, usings); } else*/ r.Cat(b, s); } else if(iscid(c)) { if(iscid(*r.Last())) r << ' '; if(s[0] == 'c' && s[1] == 'o' && s[2] == 'n' && s[3] == 's' && s[4] == 't' && !iscid(s[5])) { r << s_const; s += 5; } else if(s[0] == 'm' && s[1] == 'u' && s[2] == 't' && s[3] == 'a' && s[4] == 'b' && s[5] == 'l' && s[6] == 'e' && !iscid(s[7])) { r << "mutable"; s += 7; } else if(s[0] == 'v' && s[1] == 'o' && s[2] == 'l' && s[3] == 'a' && s[4] == 't' && s[5] == 'i' && s[6] == 'l' && s[7] == 'e' && !iscid(s[8])) { r << "volatile"; s += 8; } else { const char *b = s++; while(*s == ':' || iscid(*s)) s++; if(all) Qualify(r, nf, b, s, usings); else r.Cat(b, s); } } else { if(c == '(') all = true; if(c != ' ') r.Cat(c); s++; } } return r; } String Qualify(const CppBase& base, const String& scope, const String& type, const String& usings) { if(type.StartsWith("::")) return type.Mid(2); ScopeInfo nf(base, scope); return QualifyIds(nf, type, usings, true); } String QualifyKey(const CppBase& base, const String& scope, const String& type, const String& usings) { ScopeInfo nf(base, scope); return QualifyIds(nf, type, usings, false); } void QualifyTypes(CppBase& base, const String& scope, CppItem& m) { ScopeInfo nf(base, scope); m.qtype = QualifyIds(nf, m.type, m.using_namespaces, true); m.qptype = QualifyIds(nf, m.ptype, m.using_namespaces, true); } void QualifyPass0(CppBase& base) { // Move scopes - solve: namespace X { struct C { void Foo(); }; using namespace X; void C::Foo() {} Vector remove_scope; for(int ni = 0; ni < base.GetCount(); ni++) { Array& n = base[ni]; ScopeInfo nf(base); String scope = base.GetKey(ni); String usings; int toscopei = -1; Vector remove_item; for(int i = 0; i < n.GetCount(); i++) { CppItem& m = n[i]; if(m.qualify && m.impl) { if(usings != m.using_namespaces) { usings = m.using_namespaces; toscopei = -1; Vector h = Split(m.using_namespaces, ';'); for(int i = 0; i < h.GetCount(); i++) { String ns = h[i] + "::" + scope; toscopei = base.Find(ns); if(toscopei >= 0) break; } } if(toscopei >= 0 && toscopei != ni) { base[toscopei].Add(m); remove_item.Add(i); } } } n.Remove(remove_item); if(scope.GetCount() && n.GetCount() == 0) remove_scope.Add(ni); } base.Remove(remove_scope); } void QualifyPass1(CppBase& base) { // Qualify types LTIMING("QualifyPass1"); for(int ni = 0; ni < base.GetCount(); ni++) { Array& n = base[ni]; ScopeInfo nf(base, ni); for(int i = 0; i < n.GetCount(); i++) { CppItem& m = n[i]; if(m.kind == NAMESPACE) base.namespaces.FindAdd(base.GetKey(ni)); if(m.IsType() && m.qualify) { m.qualify = false; m.qtype = QualifyIds(nf, m.type, m.using_namespaces, true); // type of item, now qualified (probaly already was) m.qptype = QualifyIds(nf, m.ptype, m.using_namespaces, true); // base classes m.qitem = m.item; // name of type (struct) item is already qualified } } } } void QualifyPass2(CppBase& base) { // Qualify function parameters LTIMING("QualifyPass2"); for(int ni = 0; ni < base.GetCount(); ni++) { Array& n = base[ni]; ScopeInfo nf(base, ni); for(int i = 0; i < n.GetCount(); i++) { CppItem& m = n[i]; if(m.uname.GetCount() == 0 && m.name.GetCount()) m.uname = ToUpper(m.name); if(!m.IsType() && m.qualify) { m.qualify = false; m.qtype = QualifyIds(nf, m.type, m.using_namespaces, true); m.qptype = QualifyIds(nf, m.ptype, m.using_namespaces, true); m.qitem = m.IsCode() ? QualifyIds(nf, m.item, m.using_namespaces, false) : m.item; } } } } void Qualify(CppBase& base) { Md5Stream md5; Vector no = GetSortOrder(base.GetKeys()); for(int q = 0; q < base.GetCount(); q++) { int ni = no[q]; md5 << base.GetKey(ni); const Array& n = base[ni]; for(int i = 0; i < n.GetCount(); i++) { const CppItem& m = n[i]; if(m.IsType()) md5 << ';' << m.ptype; } md5 << '\n'; } String c5 = md5.FinishString(); if(c5 != base.types_md5) { // set of types changed, requalify everything base.types_md5 = c5; for(int ni = 0; ni < base.GetCount(); ni++) { Array& n = base[ni]; for(int i = 0; i < n.GetCount(); i++) n[i].qualify = true; } } base.namespaces.Clear(); QualifyPass0(base); QualifyPass1(base); QualifyPass2(base); } }