OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / shared / cplusplus / TranslationUnit.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
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.
18 **
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.
22 **
23 ** Other Usage
24 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32 // Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
33 //
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:
40 //
41 // The above copyright notice and this permission notice shall be included in
42 // all copies or substantial portions of the Software.
43 //
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
50 // THE SOFTWARE.
51
52 #include "TranslationUnit.h"
53 #include "Control.h"
54 #include "Parser.h"
55 #include "Lexer.h"
56 #include "MemoryPool.h"
57 #include "AST.h"
58 #include "Literals.h"
59 #include "DiagnosticClient.h"
60 #include <stack>
61 #include <cstdarg>
62 #include <algorithm>
63
64 #ifdef _MSC_VER
65 #    define va_copy(dst, src) ((dst) = (src))
66 #elif defined(__INTEL_COMPILER) && !defined(va_copy)
67 #    define va_copy __va_copy
68 #endif
69
70 using namespace CPlusPlus;
71
72 TranslationUnit::TranslationUnit(Control *control, const StringLiteral *fileId)
73     : _control(control),
74       _fileId(fileId),
75       _firstSourceChar(0),
76       _lastSourceChar(0),
77       _pool(0),
78       _ast(0),
79       _flags(0)
80 {
81     _tokens = new std::vector<Token>();
82     _previousTranslationUnit = control->switchTranslationUnit(this);
83     _pool = new MemoryPool();
84 }
85
86 TranslationUnit::~TranslationUnit()
87 {
88     (void) _control->switchTranslationUnit(_previousTranslationUnit);
89     delete _tokens;
90     delete _pool;
91 }
92
93 bool TranslationUnit::qtMocRunEnabled() const
94 { return f._qtMocRunEnabled; }
95
96 void TranslationUnit::setQtMocRunEnabled(bool onoff)
97 { f._qtMocRunEnabled = onoff; }
98
99 bool TranslationUnit::cxx0xEnabled() const
100 { return f._cxx0xEnabled; }
101
102 void TranslationUnit::setCxxOxEnabled(bool onoff)
103 { f._cxx0xEnabled = onoff; }
104
105 bool TranslationUnit::objCEnabled() const
106 { return f._objCEnabled; }
107
108 void TranslationUnit::setObjCEnabled(bool onoff)
109 { f._objCEnabled = onoff; }
110
111 Control *TranslationUnit::control() const
112 { return _control; }
113
114 const StringLiteral *TranslationUnit::fileId() const
115 { return _fileId; }
116
117 const char *TranslationUnit::fileName() const
118 { return _fileId->chars(); }
119
120 unsigned TranslationUnit::fileNameLength() const
121 { return _fileId->size(); }
122
123 const char *TranslationUnit::firstSourceChar() const
124 { return _firstSourceChar; }
125
126 const char *TranslationUnit::lastSourceChar() const
127 { return _lastSourceChar; }
128
129 unsigned TranslationUnit::sourceLength() const
130 { return _lastSourceChar - _firstSourceChar; }
131
132 void TranslationUnit::setSource(const char *source, unsigned size)
133 {
134     _firstSourceChar = source;
135     _lastSourceChar = source + size;
136 }
137
138 unsigned TranslationUnit::tokenCount() const
139 { return _tokens->size(); }
140
141 const Token &TranslationUnit::tokenAt(unsigned index) const
142 { return _tokens->at(index); }
143
144 int TranslationUnit::tokenKind(unsigned index) const
145 { return _tokens->at(index).f.kind; }
146
147 const char *TranslationUnit::spell(unsigned index) const
148 {
149     if (! index)
150         return 0;
151
152     return _tokens->at(index).spell();
153 }
154
155 const Identifier *TranslationUnit::identifier(unsigned index) const
156 { return _tokens->at(index).identifier; }
157
158 const Literal *TranslationUnit::literal(unsigned index) const
159 { return _tokens->at(index).literal; }
160
161 const StringLiteral *TranslationUnit::stringLiteral(unsigned index) const
162 { return _tokens->at(index).string; }
163
164 const NumericLiteral *TranslationUnit::numericLiteral(unsigned index) const
165 { return _tokens->at(index).number; }
166
167 unsigned TranslationUnit::matchingBrace(unsigned index) const
168 { return _tokens->at(index).close_brace; }
169
170 MemoryPool *TranslationUnit::memoryPool() const
171 { return _pool; }
172
173 AST *TranslationUnit::ast() const
174 { return _ast; }
175
176 bool TranslationUnit::isTokenized() const
177 { return f._tokenized; }
178
179 bool TranslationUnit::isParsed() const
180 { return f._parsed; }
181
182 void TranslationUnit::tokenize()
183 {
184     if (isTokenized())
185         return;
186
187     f._tokenized = true;
188
189     Lexer lex(this);
190     lex.setQtMocRunEnabled(f._qtMocRunEnabled);
191     lex.setCxxOxEnabled(f._cxx0xEnabled);
192     lex.setObjCEnabled(f._objCEnabled);
193
194     std::stack<unsigned> braces;
195     _tokens->push_back(Token()); // the first token needs to be invalid!
196
197     pushLineOffset(0);
198     pushPreprocessorLine(0, 1, fileId());
199
200     const Identifier *lineId   = control()->identifier("line");
201     const Identifier *genId    = control()->identifier("gen");
202
203     bool generated = false;
204     Token tk;
205     do {
206         lex(&tk);
207
208       _Lrecognize:
209         if (tk.is(T_POUND) && tk.newline()) {
210             unsigned offset = tk.offset;
211             lex(&tk);
212
213             if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == genId) {
214                 // it's a gen directive.
215                 lex(&tk);
216
217                 if (! tk.f.newline && tk.is(T_TRUE)) {
218                     lex(&tk);
219                     generated = true;
220                 } else {
221                     generated = false;
222                 }
223             } else {
224                 if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == lineId)
225                     lex(&tk);
226                 if (! tk.f.newline && tk.is(T_NUMERIC_LITERAL)) {
227                     unsigned line = (unsigned) strtoul(tk.spell(), 0, 0);
228                     lex(&tk);
229                     if (! tk.f.newline && tk.is(T_STRING_LITERAL)) {
230                         const StringLiteral *fileName = control()->stringLiteral(tk.string->chars(),
231                                                                                              tk.string->size());
232                         pushPreprocessorLine(offset, line, fileName);
233                         lex(&tk);
234                     }
235                 }
236             }
237             while (tk.isNot(T_EOF_SYMBOL) && ! tk.f.newline)
238                 lex(&tk);
239             goto _Lrecognize;
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();
244             braces.pop();
245             (*_tokens)[open_brace_index].close_brace = _tokens->size();
246         }
247         tk.f.generated = generated;
248         _tokens->push_back(tk);
249     } while (tk.f.kind);
250
251     for (; ! braces.empty(); braces.pop()) {
252         unsigned open_brace_index = braces.top();
253         (*_tokens)[open_brace_index].close_brace = _tokens->size();
254     }
255 }
256
257 bool TranslationUnit::skipFunctionBody() const
258 { return f._skipFunctionBody; }
259
260 void TranslationUnit::setSkipFunctionBody(bool skipFunctionBody)
261 { f._skipFunctionBody = skipFunctionBody; }
262
263 bool TranslationUnit::parse(ParseMode mode)
264 {
265     if (isParsed())
266         return false;
267
268     if (! isTokenized())
269         tokenize();
270
271     f._parsed = true;
272
273     Parser parser(this);
274     parser.setQtMocRunEnabled(f._qtMocRunEnabled);
275     parser.setCxxOxEnabled(f._cxx0xEnabled);
276     parser.setObjCEnabled(f._objCEnabled);
277
278     bool parsed = false;
279
280     switch (mode) {
281     case ParseTranlationUnit: {
282         TranslationUnitAST *node = 0;
283         parsed = parser.parseTranslationUnit(node);
284         _ast = node;
285     } break;
286
287     case ParseDeclaration: {
288         DeclarationAST *node = 0;
289         parsed = parser.parseDeclaration(node);
290         _ast = node;
291     } break;
292
293     case ParseExpression: {
294         ExpressionAST *node = 0;
295         parsed = parser.parseExpression(node);
296         _ast = node;
297     } break;
298
299     case ParseDeclarator: {
300         DeclaratorAST *node = 0;
301         parsed = parser.parseDeclarator(node, /*decl_specifier_list =*/ 0);
302         _ast = node;
303     } break;
304
305     case ParseStatement: {
306         StatementAST *node = 0;
307         parsed = parser.parseStatement(node);
308         _ast = node;
309     } break;
310
311     default:
312         break;
313     } // switch
314
315     return parsed;
316 }
317
318 void TranslationUnit::pushLineOffset(unsigned offset)
319 { _lineOffsets.push_back(offset); }
320
321 void TranslationUnit::pushPreprocessorLine(unsigned offset,
322                                            unsigned line,
323                                            const StringLiteral *fileName)
324 { _ppLines.push_back(PPLine(offset, line, fileName)); }
325
326 unsigned TranslationUnit::findLineNumber(unsigned offset) const
327 {
328     std::vector<unsigned>::const_iterator it =
329         std::lower_bound(_lineOffsets.begin(), _lineOffsets.end(), offset);
330
331     if (it != _lineOffsets.begin())
332         --it;
333
334     return it - _lineOffsets.begin();
335 }
336
337 TranslationUnit::PPLine TranslationUnit::findPreprocessorLine(unsigned offset) const
338 {
339     std::vector<PPLine>::const_iterator it =
340         std::lower_bound(_ppLines.begin(), _ppLines.end(), PPLine(offset));
341
342     if (it != _ppLines.begin())
343         --it;
344
345     return *it;
346 }
347
348 unsigned TranslationUnit::findColumnNumber(unsigned offset, unsigned lineNumber) const
349 {
350     if (! offset)
351         return 0;
352
353     return offset - _lineOffsets[lineNumber];
354 }
355
356 void TranslationUnit::getTokenPosition(unsigned index,
357                                        unsigned *line,
358                                        unsigned *column,
359                                        const StringLiteral **fileName) const
360 { return getPosition(tokenAt(index).offset, line, column, fileName); }
361
362 void TranslationUnit::getTokenStartPosition(unsigned index, unsigned *line,
363                                             unsigned *column,
364                                             const StringLiteral **fileName) const
365 { return getPosition(tokenAt(index).begin(), line, column, fileName); }
366
367 void TranslationUnit::getTokenEndPosition(unsigned index, unsigned *line,
368                                           unsigned *column,
369                                           const StringLiteral **fileName) const
370 { return getPosition(tokenAt(index).end(), line, column, fileName); }
371
372 void TranslationUnit::getPosition(unsigned tokenOffset,
373                                   unsigned *line,
374                                   unsigned *column,
375                                   const StringLiteral **fileName) const
376 {
377     unsigned lineNumber = findLineNumber(tokenOffset);
378     unsigned columnNumber = findColumnNumber(tokenOffset, lineNumber);
379     const PPLine ppLine = findPreprocessorLine(tokenOffset);
380
381     lineNumber -= findLineNumber(ppLine.offset) + 1;
382     lineNumber += ppLine.line;
383
384     if (line)
385         *line = lineNumber;
386
387     if (column)
388         *column = columnNumber;
389
390     if (fileName)
391        *fileName = ppLine.fileName;
392 }
393
394 bool TranslationUnit::blockErrors(bool block)
395 {
396     bool previous = f._blockErrors;
397     f._blockErrors = block;
398     return previous;
399 }
400
401 void TranslationUnit::message(DiagnosticClient::Level level, unsigned index, const char *format, va_list args)
402 {
403     if (f._blockErrors)
404         return;
405
406     index = std::min(index, tokenCount() - 1);
407
408     unsigned line = 0, column = 0;
409     const StringLiteral *fileName = 0;
410     getTokenPosition(index, &line, &column, &fileName);
411
412     if (DiagnosticClient *client = control()->diagnosticClient()) {
413         client->report(level, fileName, line, column, format, args);
414     } else {
415         fprintf(stderr, "%s:%d: ", fileName->chars(), line);
416         const char *l = "error";
417         if (level == DiagnosticClient::Warning)
418             l = "warning";
419         else if (level == DiagnosticClient::Fatal)
420             l = "fatal";
421         fprintf(stderr, "%s: ", l);
422
423         vfprintf(stderr, format, args);
424         fputc('\n', stderr);
425
426         showErrorLine(index, column, stderr);
427     }
428
429     if (level == DiagnosticClient::Fatal)
430         exit(EXIT_FAILURE);
431 }
432
433 void TranslationUnit::warning(unsigned index, const char *format, ...)
434 {
435     if (f._blockErrors)
436         return;
437
438     va_list args, ap;
439     va_start(args, format);
440     va_copy(ap, args);
441     message(DiagnosticClient::Warning, index, format, args);
442     va_end(ap);
443     va_end(args);
444 }
445
446 void TranslationUnit::error(unsigned index, const char *format, ...)
447 {
448     if (f._blockErrors)
449         return;
450
451     va_list args, ap;
452     va_start(args, format);
453     va_copy(ap, args);
454     message(DiagnosticClient::Error, index, format, args);
455     va_end(ap);
456     va_end(args);
457 }
458
459 void TranslationUnit::fatal(unsigned index, const char *format, ...)
460 {
461     if (f._blockErrors)
462         return;
463
464     va_list args, ap;
465     va_start(args, format);
466     va_copy(ap, args);
467     message(DiagnosticClient::Fatal, index, format, args);
468     va_end(ap);
469     va_end(args);
470 }
471
472 unsigned TranslationUnit::findPreviousLineOffset(unsigned tokenIndex) const
473 {
474     unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(tokenIndex).offset)];
475     return lineOffset;
476 }
477
478 void TranslationUnit::showErrorLine(unsigned index, unsigned column, FILE *out)
479 {
480     unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(index).offset)];
481     for (const char *cp = _firstSourceChar + lineOffset + 1; *cp && *cp != '\n'; ++cp) {
482         fputc(*cp, out);
483     }
484     fputc('\n', out);
485
486     const char *end = _firstSourceChar + lineOffset + 1 + column - 1;
487     for (const char *cp = _firstSourceChar + lineOffset + 1; cp != end; ++cp) {
488         if (*cp != '\t')
489             fputc(' ', out);
490         else
491             fputc('\t', out);
492     }
493     fputc('^', out);
494     fputc('\n', out);
495 }
496
497 void TranslationUnit::resetAST()
498 {
499     delete _pool;
500     _pool = 0;
501     _ast = 0;
502 }
503
504 void TranslationUnit::release()
505 {
506     resetAST();
507     delete _tokens;
508     _tokens = 0;
509 }
510
511