1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | |
4 | #include "cppwriteincludes.h" |
5 | #include "driver.h" |
6 | #include "ui4.h" |
7 | #include "uic.h" |
8 | #include "databaseinfo.h" |
9 | |
10 | #include <qdebug.h> |
11 | #include <qfileinfo.h> |
12 | #include <qtextstream.h> |
13 | |
14 | #include <stdio.h> |
15 | |
16 | QT_BEGIN_NAMESPACE |
17 | |
18 | using namespace Qt::StringLiterals; |
19 | |
20 | enum { debugWriteIncludes = 0 }; |
21 | enum { = 0 }; |
22 | |
23 | // Format a module header as 'QtCore/QObject' |
24 | static inline QString (const QString &module, const QString &) |
25 | { |
26 | QString rc = module; |
27 | rc += u'/'; |
28 | rc += header; |
29 | return rc; |
30 | } |
31 | |
32 | namespace CPP { |
33 | |
34 | WriteIncludes::WriteIncludes(Uic *uic) : WriteIncludesBase(uic), |
35 | m_output(uic->output()) |
36 | { |
37 | // When possible (no namespace) use the "QtModule/QClass" convention |
38 | // and create a re-mapping of the old header "qclass.h" to it. Do not do this |
39 | // for the "Phonon::Someclass" classes, however. |
40 | const QLatin1StringView namespaceDelimiter = "::"_L1 ; |
41 | for (const auto &e : classInfoEntries()) { |
42 | const QString klass = QLatin1StringView(e.klass); |
43 | const QString module = QLatin1StringView(e.module); |
44 | QLatin1StringView = QLatin1StringView(e.header); |
45 | if (klass.contains(s: namespaceDelimiter)) { |
46 | m_classToHeader.insert(key: klass, value: moduleHeader(module, header)); |
47 | } else { |
48 | const QString = moduleHeader(module, header: klass); |
49 | m_classToHeader.insert(key: klass, value: newHeader); |
50 | m_oldHeaderToNewHeader.insert(key: header, value: newHeader); |
51 | } |
52 | } |
53 | } |
54 | |
55 | void WriteIncludes::acceptUI(DomUI *node) |
56 | { |
57 | m_localIncludes.clear(); |
58 | m_globalIncludes.clear(); |
59 | m_includeBaseNames.clear(); |
60 | |
61 | WriteIncludesBase::acceptUI(node); |
62 | |
63 | const auto includeFile = uic()->option().includeFile; |
64 | if (!includeFile.isEmpty()) |
65 | m_globalIncludes.insert(x: includeFile); |
66 | |
67 | writeHeaders(headers: m_globalIncludes, global: true); |
68 | writeHeaders(headers: m_localIncludes, global: false); |
69 | |
70 | m_output << '\n'; |
71 | } |
72 | |
73 | void WriteIncludes::insertIncludeForClass(const QString &className, QString , bool global) |
74 | { |
75 | if (debugWriteIncludes) |
76 | fprintf(stderr, format: "%s %s '%s' %d\n" , Q_FUNC_INFO, qPrintable(className), qPrintable(header), global); |
77 | |
78 | do { |
79 | if (!header.isEmpty()) |
80 | break; |
81 | |
82 | // Known class |
83 | const StringMap::const_iterator it = m_classToHeader.constFind(key: className); |
84 | if (it != m_classToHeader.constEnd()) { |
85 | header = it.value(); |
86 | global = true; |
87 | break; |
88 | } |
89 | |
90 | // Quick check by class name to detect includehints provided for custom widgets. |
91 | // Remove namespaces |
92 | QString lowerClassName = className.toLower(); |
93 | static const auto namespaceSeparator = "::"_L1 ; |
94 | const int namespaceIndex = lowerClassName.lastIndexOf(s: namespaceSeparator); |
95 | if (namespaceIndex != -1) |
96 | lowerClassName.remove(i: 0, len: namespaceIndex + namespaceSeparator.size()); |
97 | if (m_includeBaseNames.contains(value: lowerClassName)) { |
98 | header.clear(); |
99 | break; |
100 | } |
101 | |
102 | // Last resort: Create default header |
103 | if (!uic()->option().implicitIncludes) |
104 | break; |
105 | header = lowerClassName; |
106 | header += ".h"_L1 ; |
107 | if (warnHeaderGeneration) { |
108 | qWarning(msg: "%s: Warning: generated header '%s' for class '%s'." , |
109 | qPrintable(uic()->option().messagePrefix()), |
110 | qPrintable(header), qPrintable(className)); |
111 | |
112 | } |
113 | |
114 | global = true; |
115 | } while (false); |
116 | |
117 | if (!header.isEmpty()) |
118 | insertInclude(header, global); |
119 | } |
120 | |
121 | void WriteIncludes::doAdd(const QString &className, const DomCustomWidget *dcw) |
122 | { |
123 | if (dcw != nullptr) |
124 | addCppCustomWidget(className, dcw); |
125 | else |
126 | insertIncludeForClass(className, header: {}, global: false); |
127 | } |
128 | |
129 | void WriteIncludes::addCppCustomWidget(const QString &className, const DomCustomWidget *dcw) |
130 | { |
131 | const DomHeader * = dcw->elementHeader(); |
132 | if (domHeader != nullptr && !domHeader->text().isEmpty()) { |
133 | // custom header unless it is a built-in qt class |
134 | QString ; |
135 | bool global = false; |
136 | if (!m_classToHeader.contains(key: className)) { |
137 | global = domHeader->attributeLocation().toLower() == "global"_L1 ; |
138 | header = domHeader->text(); |
139 | } |
140 | insertIncludeForClass(className, header, global); |
141 | return; |
142 | } |
143 | } |
144 | |
145 | void WriteIncludes::acceptInclude(DomInclude *node) |
146 | { |
147 | bool global = true; |
148 | if (node->hasAttributeLocation()) |
149 | global = node->attributeLocation() == "global"_L1 ; |
150 | insertInclude(header: node->text(), global); |
151 | } |
152 | |
153 | void WriteIncludes::insertInclude(const QString &, bool global) |
154 | { |
155 | if (debugWriteIncludes) |
156 | fprintf(stderr, format: "%s %s %d\n" , Q_FUNC_INFO, qPrintable(header), global); |
157 | |
158 | OrderedSet &includes = global ? m_globalIncludes : m_localIncludes; |
159 | // Insert (if not already done). |
160 | const bool = includes.insert(x: header).second; |
161 | if (!isNewHeader) |
162 | return; |
163 | // Also remember base name for quick check of suspicious custom plugins |
164 | const QString lowerBaseName = QFileInfo(header).completeBaseName ().toLower(); |
165 | m_includeBaseNames.insert(value: lowerBaseName); |
166 | } |
167 | |
168 | void WriteIncludes::(const OrderedSet &, bool global) |
169 | { |
170 | const QChar openingQuote = global ? u'<' : u'"'; |
171 | const QChar closingQuote = global ? u'>' : u'"'; |
172 | |
173 | // Check for the old headers 'qslider.h' and replace by 'QtGui/QSlider' |
174 | for (const QString & : headers) { |
175 | const QString value = m_oldHeaderToNewHeader.value(key: header, defaultValue: header); |
176 | const auto trimmed = QStringView(value).trimmed(); |
177 | if (!trimmed.isEmpty()) |
178 | m_output << "#include " << openingQuote << trimmed << closingQuote << '\n'; |
179 | } |
180 | } |
181 | |
182 | } // namespace CPP |
183 | |
184 | QT_END_NAMESPACE |
185 | |