1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the QtCore module of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 ** packaging of this file. Please review the following information to 22 ** ensure the GNU Lesser General Public License version 3 requirements 23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 ** 25 ** GNU General Public License Usage 26 ** Alternatively, this file may be used under the terms of the GNU 27 ** General Public License version 2.0 or (at your option) the GNU General 28 ** Public license version 3 or any later version approved by the KDE Free 29 ** Qt Foundation. The licenses are as published by the Free Software 30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 ** included in the packaging of this file. Please review the following 32 ** information to ensure the GNU General Public License requirements will 33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 ** https://www.gnu.org/licenses/gpl-3.0.html. 35 ** 36 ** $QT_END_LICENSE$ 37 ** 38 ****************************************************************************/ 39 40 #if !defined(QMETAOBJECT_P_H) && !defined(UTILS_H) 41 # error "Include qmetaobject_p.h (or moc's utils.h) before including this file." 42 #endif 43 44 // 45 // W A R N I N G 46 // ------------- 47 // 48 // This file is not part of the Qt API. It exists purely as an 49 // implementation detail. This header file may change from version to 50 // version without notice, or even be removed. 51 // 52 // We mean it. 53 // 54 55 #include <QtCore/private/qglobal_p.h> 56 57 QT_BEGIN_NAMESPACE 58 59 // This function is shared with moc.cpp. This file should be included where needed. 60 static QByteArray normalizeTypeInternal(const char *t, const char *e, bool fixScope = false, bool adjustConst = true) 61 { 62 int len = e - t; 63 /* 64 Convert 'char const *' into 'const char *'. Start at index 1, 65 not 0, because 'const char *' is already OK. 66 */ 67 QByteArray constbuf; 68 for (int i = 1; i < len; i++) { 69 if ( t[i] == 'c' 70 && strncmp(t + i + 1, "onst", 4) == 0 71 && (i + 5 >= len || !is_ident_char(t[i + 5])) 72 && !is_ident_char(t[i-1]) 73 ) { 74 constbuf = QByteArray(t, len); 75 if (is_space(t[i-1])) 76 constbuf.remove(i-1, 6); 77 else 78 constbuf.remove(i, 5); 79 constbuf.prepend("const "); 80 t = constbuf.data(); 81 e = constbuf.data() + constbuf.length(); 82 break; 83 } 84 /* 85 We mustn't convert 'char * const *' into 'const char **' 86 and we must beware of 'Bar<const Bla>'. 87 */ 88 if (t[i] == '&' || t[i] == '*' ||t[i] == '<') 89 break; 90 } 91 if (adjustConst && e > t + 6 && strncmp("const ", t, 6) == 0) { 92 if (*(e-1) == '&') { // treat const reference as value 93 t += 6; 94 --e; 95 } else if (is_ident_char(*(e-1)) || *(e-1) == '>') { // treat const value as value 96 t += 6; 97 } 98 } 99 QByteArray result; 100 result.reserve(len); 101 102 #if 1 103 // consume initial 'const ' 104 if (strncmp("const ", t, 6) == 0) { 105 t+= 6; 106 result += "const "; 107 } 108 #endif 109 110 // some type substitutions for 'unsigned x' 111 if (strncmp("unsigned", t, 8) == 0) { 112 // make sure "unsigned" is an isolated word before making substitutions 113 if (!t[8] || !is_ident_char(t[8])) { 114 if (strncmp(" int", t+8, 4) == 0) { 115 t += 8+4; 116 result += "uint"; 117 } else if (strncmp(" long", t+8, 5) == 0) { 118 if ((strlen(t + 8 + 5) < 4 || strncmp(t + 8 + 5, " int", 4) != 0) // preserve '[unsigned] long int' 119 && (strlen(t + 8 + 5) < 5 || strncmp(t + 8 + 5, " long", 5) != 0) // preserve '[unsigned] long long' 120 ) { 121 t += 8+5; 122 result += "ulong"; 123 } 124 } else if (strncmp(" short", t+8, 6) != 0 // preserve unsigned short 125 && strncmp(" char", t+8, 5) != 0) { // preserve unsigned char 126 // treat rest (unsigned) as uint 127 t += 8; 128 result += "uint"; 129 } 130 } 131 } else { 132 // discard 'struct', 'class', and 'enum'; they are optional 133 // and we don't want them in the normalized signature 134 struct { 135 const char *keyword; 136 int len; 137 } optional[] = { 138 { "struct ", 7 }, 139 { "class ", 6 }, 140 { "enum ", 5 }, 141 { nullptr, 0 } 142 }; 143 int i = 0; 144 do { 145 if (strncmp(optional[i].keyword, t, optional[i].len) == 0) { 146 t += optional[i].len; 147 break; 148 } 149 } while (optional[++i].keyword != nullptr); 150 } 151 152 bool star = false; 153 while (t != e) { 154 char c = *t++; 155 if (fixScope && c == ':' && *t == ':' ) { 156 ++t; 157 c = *t++; 158 int i = result.size() - 1; 159 while (i >= 0 && is_ident_char(result.at(i))) 160 --i; 161 result.resize(i + 1); 162 } 163 star = star || c == '*'; 164 result += c; 165 if (c == '<') { 166 //template recursion 167 const char* tt = t; 168 int templdepth = 1; 169 int scopeDepth = 0; 170 while (t != e) { 171 c = *t++; 172 if (c == '{' || c == '(' || c == '[') 173 ++scopeDepth; 174 if (c == '}' || c == ')' || c == ']') 175 --scopeDepth; 176 if (scopeDepth == 0) { 177 if (c == '<') 178 ++templdepth; 179 if (c == '>') 180 --templdepth; 181 if (templdepth == 0 || (templdepth == 1 && c == ',')) { 182 result += normalizeTypeInternal(tt, t-1, fixScope, false); 183 result += c; 184 if (templdepth == 0) { 185 if (*t == '>') 186 result += ' '; // avoid >> 187 break; 188 } 189 tt = t; 190 } 191 } 192 } 193 } 194 195 // cv qualifers can appear after the type as well 196 if (!is_ident_char(c) && t != e && (e - t >= 5 && strncmp("const", t, 5) == 0) 197 && (e - t == 5 || !is_ident_char(t[5]))) { 198 t += 5; 199 while (t != e && is_space(*t)) 200 ++t; 201 if (adjustConst && t != e && *t == '&') { 202 // treat const ref as value 203 ++t; 204 } else if (adjustConst && !star) { 205 // treat const as value 206 } else if (!star) { 207 // move const to the front (but not if const comes after a *) 208 result.prepend("const "); 209 } else { 210 // keep const after a * 211 result += "const"; 212 } 213 } 214 } 215 216 return result; 217 } 218 219 QT_END_NAMESPACE 220