1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
32 // Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
34 // Permission is hereby granted, free of charge, to any person obtaining a copy
35 // of this software and associated documentation files (the "Software"), to deal
36 // in the Software without restriction, including without limitation the rights
37 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38 // copies of the Software, and to permit persons to whom the Software is
39 // furnished to do so, subject to the following conditions:
41 // The above copyright notice and this permission notice shall be included in
42 // all copies or substantial portions of the Software.
44 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52 #include "TranslationUnit.h"
56 #include "MemoryPool.h"
59 #include "DiagnosticClient.h"
65 # define va_copy(dst, src) ((dst) = (src))
66 #elif defined(__INTEL_COMPILER) && !defined(va_copy)
67 # define va_copy __va_copy
70 using namespace CPlusPlus;
72 TranslationUnit::TranslationUnit(Control *control, const StringLiteral *fileId)
81 _tokens = new std::vector<Token>();
82 _previousTranslationUnit = control->switchTranslationUnit(this);
83 _pool = new MemoryPool();
86 TranslationUnit::~TranslationUnit()
88 (void) _control->switchTranslationUnit(_previousTranslationUnit);
93 bool TranslationUnit::qtMocRunEnabled() const
94 { return f._qtMocRunEnabled; }
96 void TranslationUnit::setQtMocRunEnabled(bool onoff)
97 { f._qtMocRunEnabled = onoff; }
99 bool TranslationUnit::cxx0xEnabled() const
100 { return f._cxx0xEnabled; }
102 void TranslationUnit::setCxxOxEnabled(bool onoff)
103 { f._cxx0xEnabled = onoff; }
105 bool TranslationUnit::objCEnabled() const
106 { return f._objCEnabled; }
108 void TranslationUnit::setObjCEnabled(bool onoff)
109 { f._objCEnabled = onoff; }
111 Control *TranslationUnit::control() const
114 const StringLiteral *TranslationUnit::fileId() const
117 const char *TranslationUnit::fileName() const
118 { return _fileId->chars(); }
120 unsigned TranslationUnit::fileNameLength() const
121 { return _fileId->size(); }
123 const char *TranslationUnit::firstSourceChar() const
124 { return _firstSourceChar; }
126 const char *TranslationUnit::lastSourceChar() const
127 { return _lastSourceChar; }
129 unsigned TranslationUnit::sourceLength() const
130 { return _lastSourceChar - _firstSourceChar; }
132 void TranslationUnit::setSource(const char *source, unsigned size)
134 _firstSourceChar = source;
135 _lastSourceChar = source + size;
138 unsigned TranslationUnit::tokenCount() const
139 { return _tokens->size(); }
141 const Token &TranslationUnit::tokenAt(unsigned index) const
142 { return _tokens->at(index); }
144 int TranslationUnit::tokenKind(unsigned index) const
145 { return _tokens->at(index).f.kind; }
147 const char *TranslationUnit::spell(unsigned index) const
152 return _tokens->at(index).spell();
155 const Identifier *TranslationUnit::identifier(unsigned index) const
156 { return _tokens->at(index).identifier; }
158 const Literal *TranslationUnit::literal(unsigned index) const
159 { return _tokens->at(index).literal; }
161 const StringLiteral *TranslationUnit::stringLiteral(unsigned index) const
162 { return _tokens->at(index).string; }
164 const NumericLiteral *TranslationUnit::numericLiteral(unsigned index) const
165 { return _tokens->at(index).number; }
167 unsigned TranslationUnit::matchingBrace(unsigned index) const
168 { return _tokens->at(index).close_brace; }
170 MemoryPool *TranslationUnit::memoryPool() const
173 AST *TranslationUnit::ast() const
176 bool TranslationUnit::isTokenized() const
177 { return f._tokenized; }
179 bool TranslationUnit::isParsed() const
180 { return f._parsed; }
182 void TranslationUnit::tokenize()
190 lex.setQtMocRunEnabled(f._qtMocRunEnabled);
191 lex.setCxxOxEnabled(f._cxx0xEnabled);
192 lex.setObjCEnabled(f._objCEnabled);
194 std::stack<unsigned> braces;
195 _tokens->push_back(Token()); // the first token needs to be invalid!
198 pushPreprocessorLine(0, 1, fileId());
200 const Identifier *lineId = control()->identifier("line");
201 const Identifier *genId = control()->identifier("gen");
203 bool generated = false;
209 if (tk.is(T_POUND) && tk.newline()) {
210 unsigned offset = tk.offset;
213 if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == genId) {
214 // it's a gen directive.
217 if (! tk.f.newline && tk.is(T_TRUE)) {
224 if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == lineId)
226 if (! tk.f.newline && tk.is(T_NUMERIC_LITERAL)) {
227 unsigned line = (unsigned) strtoul(tk.spell(), 0, 0);
229 if (! tk.f.newline && tk.is(T_STRING_LITERAL)) {
230 const StringLiteral *fileName = control()->stringLiteral(tk.string->chars(),
232 pushPreprocessorLine(offset, line, fileName);
237 while (tk.isNot(T_EOF_SYMBOL) && ! tk.f.newline)
240 } else if (tk.f.kind == T_LBRACE) {
241 braces.push(_tokens->size());
242 } else if (tk.f.kind == T_RBRACE && ! braces.empty()) {
243 const unsigned open_brace_index = braces.top();
245 (*_tokens)[open_brace_index].close_brace = _tokens->size();
247 tk.f.generated = generated;
248 _tokens->push_back(tk);
251 for (; ! braces.empty(); braces.pop()) {
252 unsigned open_brace_index = braces.top();
253 (*_tokens)[open_brace_index].close_brace = _tokens->size();
257 bool TranslationUnit::skipFunctionBody() const
258 { return f._skipFunctionBody; }
260 void TranslationUnit::setSkipFunctionBody(bool skipFunctionBody)
261 { f._skipFunctionBody = skipFunctionBody; }
263 bool TranslationUnit::parse(ParseMode mode)
274 parser.setQtMocRunEnabled(f._qtMocRunEnabled);
275 parser.setCxxOxEnabled(f._cxx0xEnabled);
276 parser.setObjCEnabled(f._objCEnabled);
281 case ParseTranlationUnit: {
282 TranslationUnitAST *node = 0;
283 parsed = parser.parseTranslationUnit(node);
287 case ParseDeclaration: {
288 DeclarationAST *node = 0;
289 parsed = parser.parseDeclaration(node);
293 case ParseExpression: {
294 ExpressionAST *node = 0;
295 parsed = parser.parseExpression(node);
299 case ParseDeclarator: {
300 DeclaratorAST *node = 0;
301 parsed = parser.parseDeclarator(node, /*decl_specifier_list =*/ 0);
305 case ParseStatement: {
306 StatementAST *node = 0;
307 parsed = parser.parseStatement(node);
318 void TranslationUnit::pushLineOffset(unsigned offset)
319 { _lineOffsets.push_back(offset); }
321 void TranslationUnit::pushPreprocessorLine(unsigned offset,
323 const StringLiteral *fileName)
324 { _ppLines.push_back(PPLine(offset, line, fileName)); }
326 unsigned TranslationUnit::findLineNumber(unsigned offset) const
328 std::vector<unsigned>::const_iterator it =
329 std::lower_bound(_lineOffsets.begin(), _lineOffsets.end(), offset);
331 if (it != _lineOffsets.begin())
334 return it - _lineOffsets.begin();
337 TranslationUnit::PPLine TranslationUnit::findPreprocessorLine(unsigned offset) const
339 std::vector<PPLine>::const_iterator it =
340 std::lower_bound(_ppLines.begin(), _ppLines.end(), PPLine(offset));
342 if (it != _ppLines.begin())
348 unsigned TranslationUnit::findColumnNumber(unsigned offset, unsigned lineNumber) const
353 return offset - _lineOffsets[lineNumber];
356 void TranslationUnit::getTokenPosition(unsigned index,
359 const StringLiteral **fileName) const
360 { return getPosition(tokenAt(index).offset, line, column, fileName); }
362 void TranslationUnit::getTokenStartPosition(unsigned index, unsigned *line,
364 const StringLiteral **fileName) const
365 { return getPosition(tokenAt(index).begin(), line, column, fileName); }
367 void TranslationUnit::getTokenEndPosition(unsigned index, unsigned *line,
369 const StringLiteral **fileName) const
370 { return getPosition(tokenAt(index).end(), line, column, fileName); }
372 void TranslationUnit::getPosition(unsigned tokenOffset,
375 const StringLiteral **fileName) const
377 unsigned lineNumber = findLineNumber(tokenOffset);
378 unsigned columnNumber = findColumnNumber(tokenOffset, lineNumber);
379 const PPLine ppLine = findPreprocessorLine(tokenOffset);
381 lineNumber -= findLineNumber(ppLine.offset) + 1;
382 lineNumber += ppLine.line;
388 *column = columnNumber;
391 *fileName = ppLine.fileName;
394 bool TranslationUnit::blockErrors(bool block)
396 bool previous = f._blockErrors;
397 f._blockErrors = block;
401 void TranslationUnit::message(DiagnosticClient::Level level, unsigned index, const char *format, va_list args)
406 index = std::min(index, tokenCount() - 1);
408 unsigned line = 0, column = 0;
409 const StringLiteral *fileName = 0;
410 getTokenPosition(index, &line, &column, &fileName);
412 if (DiagnosticClient *client = control()->diagnosticClient()) {
413 client->report(level, fileName, line, column, format, args);
415 fprintf(stderr, "%s:%d: ", fileName->chars(), line);
416 const char *l = "error";
417 if (level == DiagnosticClient::Warning)
419 else if (level == DiagnosticClient::Fatal)
421 fprintf(stderr, "%s: ", l);
423 vfprintf(stderr, format, args);
426 showErrorLine(index, column, stderr);
429 if (level == DiagnosticClient::Fatal)
433 void TranslationUnit::warning(unsigned index, const char *format, ...)
439 va_start(args, format);
441 message(DiagnosticClient::Warning, index, format, args);
446 void TranslationUnit::error(unsigned index, const char *format, ...)
452 va_start(args, format);
454 message(DiagnosticClient::Error, index, format, args);
459 void TranslationUnit::fatal(unsigned index, const char *format, ...)
465 va_start(args, format);
467 message(DiagnosticClient::Fatal, index, format, args);
472 unsigned TranslationUnit::findPreviousLineOffset(unsigned tokenIndex) const
474 unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(tokenIndex).offset)];
478 void TranslationUnit::showErrorLine(unsigned index, unsigned column, FILE *out)
480 unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(index).offset)];
481 for (const char *cp = _firstSourceChar + lineOffset + 1; *cp && *cp != '\n'; ++cp) {
486 const char *end = _firstSourceChar + lineOffset + 1 + column - 1;
487 for (const char *cp = _firstSourceChar + lineOffset + 1; cp != end; ++cp) {
497 void TranslationUnit::resetAST()
504 void TranslationUnit::release()