diff options
author | Joerg Bornemann <joerg.bornemann@nokia.com> | 2012-02-15 15:56:22 +0100 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2012-02-15 21:57:41 +0100 |
commit | 5672fa8fd3bd6b09125d9e143a7bb277cea2e87f (patch) | |
tree | c945b6ad76bd8c8f6af8b520cf3ce72ef298d4b5 /src/plugins/scanner |
Long live qbs!
Change-Id: I412793e868919a9ac99611616f292e7047f1ebcf
Diffstat (limited to 'src/plugins/scanner')
-rw-r--r-- | src/plugins/scanner/cpp/CPlusPlusForwardDeclarations.h | 151 | ||||
-rw-r--r-- | src/plugins/scanner/cpp/Lexer.cpp | 669 | ||||
-rw-r--r-- | src/plugins/scanner/cpp/Lexer.h | 162 | ||||
-rw-r--r-- | src/plugins/scanner/cpp/Token.cpp | 154 | ||||
-rw-r--r-- | src/plugins/scanner/cpp/Token.h | 371 | ||||
-rw-r--r-- | src/plugins/scanner/cpp/cpp.cpp | 281 | ||||
-rw-r--r-- | src/plugins/scanner/cpp/cpp.pro | 15 | ||||
-rw-r--r-- | src/plugins/scanner/cpp/cpp_global.h | 47 | ||||
-rw-r--r-- | src/plugins/scanner/qt/qt.cpp | 227 | ||||
-rw-r--r-- | src/plugins/scanner/qt/qt.pro | 12 | ||||
-rw-r--r-- | src/plugins/scanner/scanner.h | 93 | ||||
-rw-r--r-- | src/plugins/scanner/scanner.pro | 3 |
12 files changed, 2185 insertions, 0 deletions
diff --git a/src/plugins/scanner/cpp/CPlusPlusForwardDeclarations.h b/src/plugins/scanner/cpp/CPlusPlusForwardDeclarations.h new file mode 100644 index 000000000..4b8b1f1d1 --- /dev/null +++ b/src/plugins/scanner/cpp/CPlusPlusForwardDeclarations.h @@ -0,0 +1,151 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ + +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H +#define CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H + +#include <cstdlib> +#include <cstddef> + +#ifndef CPLUSPLUS_WITHOUT_QT +# include <QtCore/qglobal.h> + +//# if defined(CPLUSPLUS_BUILD_LIB) +//# define CPLUSPLUS_EXPORT Q_DECL_EXPORT +//# elif defined(CPLUSPLUS_BUILD_STATIC_LIB) +//# define CPLUSPLUS_EXPORT +//# else +//# define CPLUSPLUS_EXPORT Q_DECL_IMPORT +//# endif +//#else +# define CPLUSPLUS_EXPORT +#endif + +namespace CPlusPlus { + +class TranslationUnit; +class Control; +class MemoryPool; +class DiagnosticClient; + +class Identifier; +class Literal; +class StringLiteral; +class NumericLiteral; + +class SymbolTable; + +// names +class NameVisitor; +class Name; +class Identifier; +class TemplateNameId; +class DestructorNameId; +class OperatorNameId; +class ConversionNameId; +class QualifiedNameId; +class SelectorNameId; + +// types +class TypeMatcher; +class FullySpecifiedType; +class TypeVisitor; +class Type; +class UndefinedType; +class VoidType; +class IntegerType; +class FloatType; +class PointerToMemberType; +class PointerType; +class ReferenceType; +class ArrayType; +class NamedType; + +// symbols +class SymbolVisitor; +class Symbol; +class Scope; +class UsingNamespaceDirective; +class UsingDeclaration; +class Declaration; +class Argument; +class TypenameArgument; +class Function; +class Namespace; +class NamespaceAlias; +class Template; +class BaseClass; +class Block; +class Class; +class Enum; +class ForwardClassDeclaration; + +class Token; + +// Objective-C symbols +class ObjCBaseClass; +class ObjCBaseProtocol; +class ObjCClass; +class ObjCForwardClassDeclaration; +class ObjCProtocol; +class ObjCForwardProtocolDeclaration; +class ObjCMethod; +class ObjCPropertyDeclaration; + +} // end of namespace CPlusPlus + +#endif // CPLUSPLUS_CPLUSPLUSFORWARDDECLARATIONS_H diff --git a/src/plugins/scanner/cpp/Lexer.cpp b/src/plugins/scanner/cpp/Lexer.cpp new file mode 100644 index 000000000..6d6f22e18 --- /dev/null +++ b/src/plugins/scanner/cpp/Lexer.cpp @@ -0,0 +1,669 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ + +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "Lexer.h" +#include <cctype> + +using namespace CPlusPlus; + +Lexer::Lexer(const char *firstChar, const char *lastChar) + : _state(State_Default), + _flags(0), + _currentLine(1) +{ + setSource(firstChar, lastChar); +} + +Lexer::~Lexer() +{ } + +void Lexer::setSource(const char *firstChar, const char *lastChar) +{ + _firstChar = firstChar; + _lastChar = lastChar; + _currentChar = _firstChar - 1; + _tokenStart = _currentChar; + _yychar = '\n'; +} + +void Lexer::setStartWithNewline(bool enabled) +{ + if (enabled) + _yychar = '\n'; + else + _yychar = ' '; +} + +int Lexer::state() const +{ return _state; } + +void Lexer::setState(int state) +{ _state = state; } + +bool Lexer::qtMocRunEnabled() const +{ return f._qtMocRunEnabled; } + +void Lexer::setQtMocRunEnabled(bool onoff) +{ f._qtMocRunEnabled = onoff; } + +bool Lexer::cxx0xEnabled() const +{ return f._cxx0xEnabled; } + +void Lexer::setCxxOxEnabled(bool onoff) +{ f._cxx0xEnabled = onoff; } + +bool Lexer::objCEnabled() const +{ return f._objCEnabled; } + +void Lexer::setObjCEnabled(bool onoff) +{ f._objCEnabled = onoff; } + +bool Lexer::isIncremental() const +{ return f._isIncremental; } + +void Lexer::setIncremental(bool isIncremental) +{ f._isIncremental = isIncremental; } + +bool Lexer::scanCommentTokens() const +{ return f._scanCommentTokens; } + +void Lexer::setScanCommentTokens(bool onoff) +{ f._scanCommentTokens = onoff; } + +void Lexer::setScanAngleStringLiteralTokens(bool onoff) +{ f._scanAngleStringLiteralTokens = onoff; } + +void Lexer::pushLineStartOffset() +{ + ++_currentLine; +} + +unsigned Lexer::tokenOffset() const +{ return _tokenStart - _firstChar; } + +unsigned Lexer::tokenLength() const +{ return _currentChar - _tokenStart; } + +const char *Lexer::tokenBegin() const +{ return _tokenStart; } + +const char *Lexer::tokenEnd() const +{ return _currentChar; } + +unsigned Lexer::currentLine() const +{ return _currentLine; } + +void Lexer::scan(Token *tok) +{ + tok->reset(); + scan_helper(tok); + tok->f.length = _currentChar - _tokenStart; +} + +void Lexer::scan_helper(Token *tok) +{ + _Lagain: + while (_yychar && std::isspace(_yychar)) { + if (_yychar == '\n') { + tok->f.joined = false; + tok->f.newline = true; + } else { + tok->f.whitespace = true; + } + yyinp(); + } + + tok->lineno = _currentLine; + _tokenStart = _currentChar; + tok->offset = _currentChar - _firstChar; + + if (_state == State_MultiLineComment || _state == State_MultiLineDoxyComment) { + const int originalState = _state; + + if (! _yychar) { + tok->f.kind = T_EOF_SYMBOL; + return; + } + + while (_yychar) { + if (_yychar != '*') + yyinp(); + else { + yyinp(); + if (_yychar == '/') { + yyinp(); + _state = State_Default; + break; + } + } + } + + if (! f._scanCommentTokens) + goto _Lagain; + + else if (originalState == State_MultiLineComment) + tok->f.kind = T_COMMENT; + else + tok->f.kind = T_DOXY_COMMENT; + return; // done + } + + if (! _yychar) { + tok->f.kind = T_EOF_SYMBOL; + return; + } + + unsigned char ch = _yychar; + yyinp(); + + switch (ch) { + case '\\': + while (_yychar != '\n' && std::isspace(_yychar)) + yyinp(); + // ### assert(! _yychar || _yychar == '\n'); + if (_yychar == '\n') { + tok->f.joined = true; + tok->f.newline = false; + yyinp(); + } + goto _Lagain; + + case '"': case '\'': { + const char quote = ch; + + tok->f.kind = quote == '"' + ? T_STRING_LITERAL + : T_CHAR_LITERAL; + + while (_yychar && _yychar != quote) { + if (_yychar == '\n') + break; + else if (_yychar != '\\') + yyinp(); + else { + yyinp(); // skip `\\' + + if (_yychar) + yyinp(); + } + } + // assert(_yychar == quote); + + if (_yychar == quote) + yyinp(); + } break; + + case '{': + tok->f.kind = T_LBRACE; + break; + + case '}': + tok->f.kind = T_RBRACE; + break; + + case '[': + tok->f.kind = T_LBRACKET; + break; + + case ']': + tok->f.kind = T_RBRACKET; + break; + + case '#': + if (_yychar == '#') { + tok->f.kind = T_POUND_POUND; + yyinp(); + } else { + tok->f.kind = T_POUND; + } + break; + + case '(': + tok->f.kind = T_LPAREN; + break; + + case ')': + tok->f.kind = T_RPAREN; + break; + + case ';': + tok->f.kind = T_SEMICOLON; + break; + + case ':': + if (_yychar == ':') { + yyinp(); + tok->f.kind = T_COLON_COLON; + } else { + tok->f.kind = T_COLON; + } + break; + + case '.': + if (_yychar == '*') { + yyinp(); + tok->f.kind = T_DOT_STAR; + } else if (_yychar == '.') { + yyinp(); + // ### assert(_yychar); + if (_yychar == '.') { + yyinp(); + tok->f.kind = T_DOT_DOT_DOT; + } else { + tok->f.kind = T_ERROR; + } + } else if (std::isdigit(_yychar)) { + do { + if (_yychar == 'e' || _yychar == 'E') { + yyinp(); + if (_yychar == '-' || _yychar == '+') { + yyinp(); + // ### assert(std::isdigit(_yychar)); + } + } else if (std::isalnum(_yychar) || _yychar == '.') { + yyinp(); + } else { + break; + } + } while (_yychar); + tok->f.kind = T_NUMERIC_LITERAL; + } else { + tok->f.kind = T_DOT; + } + break; + + case '?': + tok->f.kind = T_QUESTION; + break; + + case '+': + if (_yychar == '+') { + yyinp(); + tok->f.kind = T_PLUS_PLUS; + } else if (_yychar == '=') { + yyinp(); + tok->f.kind = T_PLUS_EQUAL; + } else { + tok->f.kind = T_PLUS; + } + break; + + case '-': + if (_yychar == '-') { + yyinp(); + tok->f.kind = T_MINUS_MINUS; + } else if (_yychar == '=') { + yyinp(); + tok->f.kind = T_MINUS_EQUAL; + } else if (_yychar == '>') { + yyinp(); + if (_yychar == '*') { + yyinp(); + tok->f.kind = T_ARROW_STAR; + } else { + tok->f.kind = T_ARROW; + } + } else { + tok->f.kind = T_MINUS; + } + break; + + case '*': + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_STAR_EQUAL; + } else { + tok->f.kind = T_STAR; + } + break; + + case '/': + if (_yychar == '/') { + yyinp(); + + bool doxy = false; + + if (_yychar == '/' || _yychar == '!') { + yyinp(); + + if (_yychar == '<') + yyinp(); + + if (_yychar != '\n' && std::isspace(_yychar)) + doxy = true; + } + + while (_yychar && _yychar != '\n') + yyinp(); + + if (! f._scanCommentTokens) + goto _Lagain; + + tok->f.kind = doxy ? T_CPP_DOXY_COMMENT : T_CPP_COMMENT; + + } else if (_yychar == '*') { + yyinp(); + + bool doxy = false; + + if (_yychar == '*' || _yychar == '!') { + const char ch = _yychar; + + yyinp(); + + if (ch == '*' && _yychar == '/') + goto _Ldone; + + if (_yychar == '<') + yyinp(); + + if (! _yychar || std::isspace(_yychar)) + doxy = true; + } + + while (_yychar) { + if (_yychar != '*') { + yyinp(); + } else { + yyinp(); + if (_yychar == '/') + break; + } + } + + _Ldone: + if (_yychar) + yyinp(); + else + _state = doxy ? State_MultiLineDoxyComment : State_MultiLineComment; + + if (! f._scanCommentTokens) + goto _Lagain; + + tok->f.kind = doxy ? T_DOXY_COMMENT : T_COMMENT; + + } else if (_yychar == '=') { + yyinp(); + tok->f.kind = T_SLASH_EQUAL; + } else { + tok->f.kind = T_SLASH; + } + break; + + case '%': + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_PERCENT_EQUAL; + } else { + tok->f.kind = T_PERCENT; + } + break; + + case '^': + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_CARET_EQUAL; + } else { + tok->f.kind = T_CARET; + } + break; + + case '&': + if (_yychar == '&') { + yyinp(); + tok->f.kind = T_AMPER_AMPER; + } else if (_yychar == '=') { + yyinp(); + tok->f.kind = T_AMPER_EQUAL; + } else { + tok->f.kind = T_AMPER; + } + break; + + case '|': + if (_yychar == '|') { + yyinp(); + tok->f.kind = T_PIPE_PIPE; + } else if (_yychar == '=') { + yyinp(); + tok->f.kind = T_PIPE_EQUAL; + } else { + tok->f.kind = T_PIPE; + } + break; + + case '~': + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_TILDE_EQUAL; + } else { + tok->f.kind = T_TILDE; + } + break; + + case '!': + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_EXCLAIM_EQUAL; + } else { + tok->f.kind = T_EXCLAIM; + } + break; + + case '=': + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_EQUAL_EQUAL; + } else { + tok->f.kind = T_EQUAL; + } + break; + + case '<': + if (f._scanAngleStringLiteralTokens) { + const char *yytext = _currentChar; + while (_yychar && _yychar != '>') + yyinp(); + int yylen = _currentChar - yytext; + // ### assert(_yychar == '>'); + if (_yychar == '>') + yyinp(); + tok->f.kind = T_ANGLE_STRING_LITERAL; + } else if (_yychar == '<') { + yyinp(); + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_LESS_LESS_EQUAL; + } else + tok->f.kind = T_LESS_LESS; + } else if (_yychar == '=') { + yyinp(); + tok->f.kind = T_LESS_EQUAL; + } else { + tok->f.kind = T_LESS; + } + break; + + case '>': + if (_yychar == '>') { + yyinp(); + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_GREATER_GREATER_EQUAL; + } else + tok->f.kind = T_LESS_LESS; + tok->f.kind = T_GREATER_GREATER; + } else if (_yychar == '=') { + yyinp(); + tok->f.kind = T_GREATER_EQUAL; + } else { + tok->f.kind = T_GREATER; + } + break; + + case ',': + tok->f.kind = T_COMMA; + break; + + default: { + if (f._objCEnabled) { + if (ch == '@' && _yychar >= 'a' && _yychar <= 'z') { + const char *yytext = _currentChar; + + do { + yyinp(); + if (! (isalnum(_yychar) || _yychar == '_' || _yychar == '$')) + break; + } while (_yychar); + + const int yylen = _currentChar - yytext; + //tok->f.kind = classifyObjCAtKeyword(yytext, yylen); /// ### FIXME + break; + } else if (ch == '@' && _yychar == '"') { + // objc @string literals + ch = _yychar; + yyinp(); + tok->f.kind = T_AT_STRING_LITERAL; + + const char *yytext = _currentChar; + + while (_yychar && _yychar != '"') { + if (_yychar != '\\') + yyinp(); + else { + yyinp(); // skip `\\' + + if (_yychar) + yyinp(); + } + } + // assert(_yychar == '"'); + + int yylen = _currentChar - yytext; + + if (_yychar == '"') + yyinp(); + + break; + } + } + + if (ch == 'L' && (_yychar == '"' || _yychar == '\'')) { + // wide char/string literals + ch = _yychar; + yyinp(); + + const char quote = ch; + + tok->f.kind = quote == '"' + ? T_WIDE_STRING_LITERAL + : T_WIDE_CHAR_LITERAL; + + const char *yytext = _currentChar; + + while (_yychar && _yychar != quote) { + if (_yychar != '\\') + yyinp(); + else { + yyinp(); // skip `\\' + + if (_yychar) + yyinp(); + } + } + // assert(_yychar == quote); + + int yylen = _currentChar - yytext; + + if (_yychar == quote) + yyinp(); + + } else if (std::isalpha(ch) || ch == '_' || ch == '$') { + const char *yytext = _currentChar - 1; + while (std::isalnum(_yychar) || _yychar == '_' || _yychar == '$') + yyinp(); + int yylen = _currentChar - yytext; + tok->f.kind = T_IDENTIFIER; + break; + } else if (std::isdigit(ch)) { + const char *yytext = _currentChar - 1; + while (_yychar) { + if (_yychar == 'e' || _yychar == 'E') { + yyinp(); + if (_yychar == '-' || _yychar == '+') { + yyinp(); + // ### assert(std::isdigit(_yychar)); + } + } else if (std::isalnum(_yychar) || _yychar == '.') { + yyinp(); + } else { + break; + } + } + int yylen = _currentChar - yytext; + tok->f.kind = T_NUMERIC_LITERAL; + break; + } else { + tok->f.kind = T_ERROR; + break; + } + } // default + + } // switch +} + + diff --git a/src/plugins/scanner/cpp/Lexer.h b/src/plugins/scanner/cpp/Lexer.h new file mode 100644 index 000000000..e697bad9a --- /dev/null +++ b/src/plugins/scanner/cpp/Lexer.h @@ -0,0 +1,162 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ + +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CPLUSPLUS_LEXER_H +#define CPLUSPLUS_LEXER_H + +#include "CPlusPlusForwardDeclarations.h" +#include "Token.h" + + +namespace CPlusPlus { + +class CPLUSPLUS_EXPORT Lexer +{ + Lexer(const Lexer &other); + void operator =(const Lexer &other); + +public: + enum State { + State_Default, + State_MultiLineComment, + State_MultiLineDoxyComment + }; + + Lexer(const char *firstChar, const char *lastChar); + ~Lexer(); + + bool qtMocRunEnabled() const; + void setQtMocRunEnabled(bool onoff); + + bool cxx0xEnabled() const; + void setCxxOxEnabled(bool onoff); + + bool objCEnabled() const; + void setObjCEnabled(bool onoff); + + void scan(Token *tok); + + inline void operator()(Token *tok) + { scan(tok); } + + unsigned tokenOffset() const; + unsigned tokenLength() const; + const char *tokenBegin() const; + const char *tokenEnd() const; + unsigned currentLine() const; + + bool scanCommentTokens() const; + void setScanCommentTokens(bool onoff); + + bool scanAngleStringLiteralTokens() const; + void setScanAngleStringLiteralTokens(bool onoff); + + void setStartWithNewline(bool enabled); + + int state() const; + void setState(int state); + + bool isIncremental() const; + void setIncremental(bool isIncremental); + +private: + void scan_helper(Token *tok); + void setSource(const char *firstChar, const char *lastChar); + static int classify(const char *string, int length, bool q, bool cxx0x); + static int classifyObjCAtKeyword(const char *s, int n); + static int classifyOperator(const char *string, int length); + + inline void yyinp() + { + if (++_currentChar == _lastChar) + _yychar = 0; + else { + _yychar = *_currentChar; + if (_yychar == '\n') + pushLineStartOffset(); + } + } + + void pushLineStartOffset(); + +private: + struct Flags { + unsigned _isIncremental: 1; + unsigned _scanCommentTokens: 1; + unsigned _scanAngleStringLiteralTokens: 1; + unsigned _qtMocRunEnabled: 1; + unsigned _cxx0xEnabled: 1; + unsigned _objCEnabled: 1; + }; + + const char *_firstChar; + const char *_currentChar; + const char *_lastChar; + const char *_tokenStart; + unsigned char _yychar; + int _state; + union { + unsigned _flags; + Flags f; + }; + unsigned _currentLine; +}; + +} // end of namespace CPlusPlus + + +#endif // CPLUSPLUS_LEXER_H diff --git a/src/plugins/scanner/cpp/Token.cpp b/src/plugins/scanner/cpp/Token.cpp new file mode 100644 index 000000000..066e3c469 --- /dev/null +++ b/src/plugins/scanner/cpp/Token.cpp @@ -0,0 +1,154 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ + +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "Token.h" +#ifndef CPLUSPLUS_NO_PARSER +# include "Literals.h" +#endif + +using namespace CPlusPlus; + +static const char *token_names[] = { + (""), ("<error>"), + + ("<C++ comment>"), ("<C++ doxy comment>"), + ("<comment>"), ("<doxy comment>"), + + ("<identifier>"), ("<numeric literal>"), ("<char literal>"), + ("<wide char literal>"), ("<string literal>"), ("<wide char literal>"), + ("<@string literal>"), ("<angle string literal>"), + + ("&"), ("&&"), ("&="), ("->"), ("->*"), ("^"), ("^="), (":"), ("::"), + (","), ("/"), ("/="), ("."), ("..."), (".*"), ("="), ("=="), ("!"), + ("!="), (">"), (">="), (">>"), (">>="), ("{"), ("["), ("<"), ("<="), + ("<<"), ("<<="), ("("), ("-"), ("-="), ("--"), ("%"), ("%="), ("|"), + ("|="), ("||"), ("+"), ("+="), ("++"), ("#"), ("##"), ("?"), ("}"), + ("]"), (")"), (";"), ("*"), ("*="), ("~"), ("~="), + + ("asm"), ("auto"), ("bool"), ("break"), ("case"), ("catch"), ("char"), + ("class"), ("const"), ("const_cast"), ("continue"), ("default"), + ("delete"), ("do"), ("double"), ("dynamic_cast"), ("else"), ("enum"), + ("explicit"), ("export"), ("extern"), ("false"), ("float"), ("for"), + ("friend"), ("goto"), ("if"), ("inline"), ("int"), ("long"), + ("mutable"), ("namespace"), ("new"), ("operator"), ("private"), + ("protected"), ("public"), ("register"), ("reinterpret_cast"), + ("return"), ("short"), ("signed"), ("sizeof"), ("static"), + ("static_cast"), ("struct"), ("switch"), ("template"), ("this"), + ("throw"), ("true"), ("try"), ("typedef"), ("typeid"), ("typename"), + ("union"), ("unsigned"), ("using"), ("virtual"), ("void"), + ("volatile"), ("wchar_t"), ("while"), + + // gnu + ("__attribute__"), ("__typeof__"), + + // objc @keywords + ("@catch"), ("@class"), ("@compatibility_alias"), ("@defs"), ("@dynamic"), + ("@encode"), ("@end"), ("@finally"), ("@implementation"), ("@interface"), + ("@not_keyword"), ("@optional"), ("@package"), ("@private"), ("@property"), + ("@protected"), ("@protocol"), ("@public"), ("@required"), ("@selector"), + ("@synchronized"), ("@synthesize"), ("@throw"), ("@try"), + + // Qt keywords + ("SIGNAL"), ("SLOT"), ("Q_SIGNAL"), ("Q_SLOT"), ("signals"), ("slots"), + ("Q_FOREACH"), ("Q_D"), ("Q_Q"), + ("Q_INVOKABLE"), ("Q_PROPERTY"), ("Q_INTERFACES"), ("Q_ENUMS"), ("Q_FLAGS"), + ("Q_PRIVATE_SLOT"), ("Q_DECLARE_INTERFACE"), ("Q_OBJECT"), ("Q_GADGET"), + +}; + +Token::Token() : + flags(0), offset(0), ptr(0) +{ +} + +Token::~Token() +{ +} + +void Token::reset() +{ + flags = 0; + offset = 0; + ptr = 0; +} + +const char *Token::name(int kind) +{ return token_names[kind]; } + +#ifndef CPLUSPLUS_NO_PARSER +const char *Token::spell() const +{ + switch (f.kind) { + case T_IDENTIFIER: + return identifier->chars(); + + case T_NUMERIC_LITERAL: + case T_CHAR_LITERAL: + case T_STRING_LITERAL: + case T_AT_STRING_LITERAL: + case T_ANGLE_STRING_LITERAL: + case T_WIDE_CHAR_LITERAL: + case T_WIDE_STRING_LITERAL: + return literal->chars(); + + default: + return token_names[f.kind]; + } // switch +} +#endif + + diff --git a/src/plugins/scanner/cpp/Token.h b/src/plugins/scanner/cpp/Token.h new file mode 100644 index 000000000..140af2f42 --- /dev/null +++ b/src/plugins/scanner/cpp/Token.h @@ -0,0 +1,371 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ + +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CPLUSPLUS_TOKEN_H +#define CPLUSPLUS_TOKEN_H + +#include "CPlusPlusForwardDeclarations.h" + +namespace CPlusPlus { + +enum Kind { + T_EOF_SYMBOL = 0, + T_ERROR, + + T_CPP_COMMENT, + T_CPP_DOXY_COMMENT, + T_COMMENT, + T_DOXY_COMMENT, + T_IDENTIFIER, + + T_FIRST_LITERAL, + T_NUMERIC_LITERAL = T_FIRST_LITERAL, + T_CHAR_LITERAL, + T_WIDE_CHAR_LITERAL, + T_STRING_LITERAL, + T_WIDE_STRING_LITERAL, + T_AT_STRING_LITERAL, + T_ANGLE_STRING_LITERAL, + T_LAST_LITERAL = T_ANGLE_STRING_LITERAL, + + T_FIRST_OPERATOR, + T_AMPER = T_FIRST_OPERATOR, + T_AMPER_AMPER, + T_AMPER_EQUAL, + T_ARROW, + T_ARROW_STAR, + T_CARET, + T_CARET_EQUAL, + T_COLON, + T_COLON_COLON, + T_COMMA, + T_SLASH, + T_SLASH_EQUAL, + T_DOT, + T_DOT_DOT_DOT, + T_DOT_STAR, + T_EQUAL, + T_EQUAL_EQUAL, + T_EXCLAIM, + T_EXCLAIM_EQUAL, + T_GREATER, + T_GREATER_EQUAL, + T_GREATER_GREATER, + T_GREATER_GREATER_EQUAL, + T_LBRACE, + T_LBRACKET, + T_LESS, + T_LESS_EQUAL, + T_LESS_LESS, + T_LESS_LESS_EQUAL, + T_LPAREN, + T_MINUS, + T_MINUS_EQUAL, + T_MINUS_MINUS, + T_PERCENT, + T_PERCENT_EQUAL, + T_PIPE, + T_PIPE_EQUAL, + T_PIPE_PIPE, + T_PLUS, + T_PLUS_EQUAL, + T_PLUS_PLUS, + T_POUND, + T_POUND_POUND, + T_QUESTION, + T_RBRACE, + T_RBRACKET, + T_RPAREN, + T_SEMICOLON, + T_STAR, + T_STAR_EQUAL, + T_TILDE, + T_TILDE_EQUAL, + T_LAST_OPERATOR = T_TILDE_EQUAL, + + T_FIRST_KEYWORD, + T_ASM = T_FIRST_KEYWORD, + T_AUTO, + T_BOOL, + T_BREAK, + T_CASE, + T_CATCH, + T_CHAR, + T_CLASS, + T_CONST, + T_CONST_CAST, + T_CONTINUE, + T_DEFAULT, + T_DELETE, + T_DO, + T_DOUBLE, + T_DYNAMIC_CAST, + T_ELSE, + T_ENUM, + T_EXPLICIT, + T_EXPORT, + T_EXTERN, + T_FALSE, + T_FLOAT, + T_FOR, + T_FRIEND, + T_GOTO, + T_IF, + T_INLINE, + T_INT, + T_LONG, + T_MUTABLE, + T_NAMESPACE, + T_NEW, + T_OPERATOR, + T_PRIVATE, + T_PROTECTED, + T_PUBLIC, + T_REGISTER, + T_REINTERPRET_CAST, + T_RETURN, + T_SHORT, + T_SIGNED, + T_SIZEOF, + T_STATIC, + T_STATIC_CAST, + T_STRUCT, + T_SWITCH, + T_TEMPLATE, + T_THIS, + T_THROW, + T_TRUE, + T_TRY, + T_TYPEDEF, + T_TYPEID, + T_TYPENAME, + T_UNION, + T_UNSIGNED, + T_USING, + T_VIRTUAL, + T_VOID, + T_VOLATILE, + T_WCHAR_T, + T_WHILE, + + T___ATTRIBUTE__, + T___TYPEOF__, + + // obj c++ @ keywords + T_FIRST_OBJC_AT_KEYWORD, + + T_AT_CATCH = T_FIRST_OBJC_AT_KEYWORD, + T_AT_CLASS, + T_AT_COMPATIBILITY_ALIAS, + T_AT_DEFS, + T_AT_DYNAMIC, + T_AT_ENCODE, + T_AT_END, + T_AT_FINALLY, + T_AT_IMPLEMENTATION, + T_AT_INTERFACE, + T_AT_NOT_KEYWORD, + T_AT_OPTIONAL, + T_AT_PACKAGE, + T_AT_PRIVATE, + T_AT_PROPERTY, + T_AT_PROTECTED, + T_AT_PROTOCOL, + T_AT_PUBLIC, + T_AT_REQUIRED, + T_AT_SELECTOR, + T_AT_SYNCHRONIZED, + T_AT_SYNTHESIZE, + T_AT_THROW, + T_AT_TRY, + + T_LAST_OBJC_AT_KEYWORD = T_AT_TRY, + + T_FIRST_QT_KEYWORD, + + // Qt keywords + T_SIGNAL = T_FIRST_QT_KEYWORD, + T_SLOT, + T_Q_SIGNAL, + T_Q_SLOT, + T_Q_SIGNALS, + T_Q_SLOTS, + T_Q_FOREACH, + T_Q_D, + T_Q_Q, + T_Q_INVOKABLE, + T_Q_PROPERTY, + T_Q_INTERFACES, + T_Q_ENUMS, + T_Q_FLAGS, + T_Q_PRIVATE_SLOT, + T_Q_DECLARE_INTERFACE, + T_Q_OBJECT, + T_Q_GADGET, + T_LAST_KEYWORD = T_Q_GADGET, + + // aliases + T_OR = T_PIPE_PIPE, + T_AND = T_AMPER_AMPER, + T_NOT = T_EXCLAIM, + T_XOR = T_CARET, + T_BITOR = T_PIPE, + T_COMPL = T_TILDE, + T_OR_EQ = T_PIPE_EQUAL, + T_AND_EQ = T_AMPER_EQUAL, + T_BITAND = T_AMPER, + T_NOT_EQ = T_EXCLAIM_EQUAL, + T_XOR_EQ = T_CARET_EQUAL, + + T___ASM = T_ASM, + T___ASM__ = T_ASM, + + T_TYPEOF = T___TYPEOF__, + T___TYPEOF = T___TYPEOF__, + + T___INLINE = T_INLINE, + T___INLINE__ = T_INLINE, + + T___CONST = T_CONST, + T___CONST__ = T_CONST, + + T___VOLATILE = T_VOLATILE, + T___VOLATILE__ = T_VOLATILE, + + T___ATTRIBUTE = T___ATTRIBUTE__ +}; + +class CPLUSPLUS_EXPORT Token +{ +public: + Token(); + ~Token(); + + inline bool is(unsigned k) const { return f.kind == k; } + inline bool isNot(unsigned k) const { return f.kind != k; } +#ifndef CPLUSPLUS_NO_PARSER + const char *spell() const; +#endif + void reset(); + + inline unsigned kind() const { return f.kind; } + inline bool newline() const { return f.newline; } + inline bool whitespace() const { return f.whitespace; } + inline bool joined() const { return f.joined; } + inline bool expanded() const { return f.expanded; } + inline bool generated() const { return f.generated; } + inline unsigned length() const { return f.length; } + + inline unsigned begin() const + { return offset; } + + inline unsigned end() const + { return offset + f.length; } + + inline bool isLiteral() const + { return f.kind >= T_FIRST_LITERAL && f.kind <= T_LAST_LITERAL; } + + inline bool isOperator() const + { return f.kind >= T_FIRST_OPERATOR && f.kind <= T_LAST_OPERATOR; } + + inline bool isKeyword() const + { return f.kind >= T_FIRST_KEYWORD && f.kind < T_FIRST_QT_KEYWORD; } + + inline bool isComment() const + { return f.kind == T_COMMENT || f.kind == T_DOXY_COMMENT || + f.kind == T_CPP_COMMENT || f.kind == T_CPP_DOXY_COMMENT; } + + inline bool isObjCAtKeyword() const + { return f.kind >= T_FIRST_OBJC_AT_KEYWORD && f.kind <= T_LAST_OBJC_AT_KEYWORD; } + + static const char *name(int kind); + +public: + struct Flags { + unsigned kind : 8; + unsigned newline : 1; + unsigned whitespace : 1; + unsigned joined : 1; + unsigned expanded : 1; + unsigned generated : 1; + unsigned pad : 3; + unsigned length : 16; + }; + union { + unsigned flags; + Flags f; + }; + + unsigned offset; + + union { + void *ptr; +#ifndef CPLUSPLUS_NO_PARSER + const Literal *literal; + const NumericLiteral *number; + const StringLiteral *string; + const Identifier *identifier; +#endif + unsigned close_brace; + unsigned lineno; + }; +}; + +} // end of namespace CPlusPlus + + +#endif // CPLUSPLUS_TOKEN_H diff --git a/src/plugins/scanner/cpp/cpp.cpp b/src/plugins/scanner/cpp/cpp.cpp new file mode 100644 index 000000000..3fde5b6cc --- /dev/null +++ b/src/plugins/scanner/cpp/cpp.cpp @@ -0,0 +1,281 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ + +#include "../scanner.h" +#include "cpp_global.h" +#include <Lexer.h> + +using namespace CPlusPlus; + +#ifdef Q_OS_UNIX +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <unistd.h> +#else +#include <QtCore/QFile> +#endif + +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <QtCore/QScopedPointer> +#include <QtCore/QString> + +struct ScanResult +{ + char *fileName; + unsigned int size; + int flags; +}; + +struct Opaq +{ + enum FileType + { + FT_UNKNOWN, FT_HPP, FT_CPP + }; + + Opaq() + : +#ifdef Q_OS_UNIX + fd(0), + mapl(0), +#endif + fileContent(0), + fileType(FT_UNKNOWN), + hasQObjectMacro(false), + currentResultIndex(0) + {} + + ~Opaq() + { +#ifdef Q_OS_UNIX + if (fileContent) + munmap(fileContent, mapl); + if (fd) + close(fd); +#endif + } + +#ifdef Q_OS_WIN + QFile file; +#endif +#ifdef Q_OS_UNIX + int fd; + size_t mapl; +#endif + + QString fileName; + char *fileContent; + FileType fileType; + QList<ScanResult> includedFiles; + bool hasQObjectMacro; + int currentResultIndex; +}; + +static void scanCppFile(void *opaq, Lexer &yylex, bool scanForFileTags) +{ + static const size_t lengthOfIncludeLiteral = strlen("include"); + Opaq *opaque = static_cast<Opaq *>(opaq); + Token tk; + ScanResult scanResult; + + yylex(&tk); + + while (tk.isNot(T_EOF_SYMBOL)) { + if (tk.newline() && tk.is(T_POUND)) { + yylex(&tk); + + if (!scanForFileTags && !tk.newline() && tk.is(T_IDENTIFIER)) { + if (tk.length() >= lengthOfIncludeLiteral + && (strncmp(opaque->fileContent + tk.begin(), "include", lengthOfIncludeLiteral) == 0)) + { + yylex.setScanAngleStringLiteralTokens(true); + yylex(&tk); + yylex.setScanAngleStringLiteralTokens(false); + + if (!tk.newline() && (tk.is(T_STRING_LITERAL) || tk.is(T_ANGLE_STRING_LITERAL))) { + scanResult.size = tk.length() - 2; + if (tk.is(T_STRING_LITERAL)) + scanResult.flags = SC_LOCAL_INCLUDE_FLAG; + else + scanResult.flags = SC_GLOBAL_INCLUDE_FLAG; + scanResult.fileName = opaque->fileContent + tk.begin() + 1; + opaque->includedFiles.append(scanResult); + } + } + } + } else if (tk.is(T_IDENTIFIER) && !opaque->hasQObjectMacro) { + if (scanForFileTags + && tk.length() == 8 + && opaque->fileContent[tk.begin()] == 'Q' + && opaque->fileContent[tk.begin() + 1] == '_' + && (strncmp(opaque->fileContent + tk.begin() + 2, "OBJECT", 6) == 0 + || strncmp(opaque->fileContent + tk.begin() + 2, "GADGET", 6) == 0)) + { + opaque->hasQObjectMacro = true; + break; + } + } + yylex(&tk); + } +} + +static void *openScanner(const unsigned short *filePath, char **fileTags, int numFileTags) +{ + QScopedPointer<Opaq> opaque(new Opaq); + opaque->fileName = QString::fromUtf16(filePath); + + size_t mapl = 0; +#ifdef Q_OS_UNIX + QString filePathS = opaque->fileName; + + opaque->fd = open(qPrintable(filePathS), O_RDONLY); + if (opaque->fd == -1) { + opaque->fd = 0; + return 0; + } + + struct stat s; + int r = fstat(opaque->fd, &s); + if (r != 0) + return 0; + mapl = s.st_size; + opaque->mapl = mapl; + + void *vmap = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, opaque->fd, 0); + if (vmap == MAP_FAILED) + return 0; +#else + opaque->file.setFileName(opaque->fileName); + if (!opaque->file.open(QFile::ReadOnly)) + return 0; + + uchar *vmap = opaque->file.map(0, opaque->file.size()); + mapl = opaque->file.size(); +#endif + if (!vmap) + return 0; + + for (int i=0; i < numFileTags; ++i) { + const char *fileTag = fileTags[i]; + if (strncmp("cpp", fileTag, 3) == 0) + opaque->fileType = Opaq::FT_CPP; + else if (strncmp("hpp", fileTag, 3) == 0) + opaque->fileType = Opaq::FT_HPP; + } + + opaque->fileContent = reinterpret_cast<char *>(vmap); + Lexer lex(opaque->fileContent, opaque->fileContent + mapl); + const bool scanForFileTags = fileTags && numFileTags; + scanCppFile(opaque.data(), lex, scanForFileTags); + return static_cast<void *>(opaque.take()); +} + +static void closeScanner(void *ptr) +{ + Opaq *opaque = static_cast<Opaq *>(ptr); + delete opaque; +} + +static const char *next(void *opaq, int *size, int *flags) +{ + Opaq *opaque = static_cast<Opaq*>(opaq); + if (opaque->currentResultIndex < opaque->includedFiles.count()) { + const ScanResult &result = opaque->includedFiles.at(opaque->currentResultIndex); + ++opaque->currentResultIndex; + *size = result.size; + *flags = result.flags; + return result.fileName; + } + *size = 0; + *flags = 0; + return 0; +} + +static const char **additionalFileTags(void *opaq, int *size) +{ + static const char *thMocCpp[] = { "moc_cpp" }; + static const char *thMocHpp[] = { "moc_hpp" }; + + Opaq *opaque = static_cast<Opaq*>(opaq); + if (opaque->hasQObjectMacro) { + *size = 1; + switch (opaque->fileType) { + case Opaq::FT_CPP: + return thMocCpp; + case Opaq::FT_HPP: + return thMocHpp; + default: + break; + } + } + *size = 0; + return 0; +} + +extern "C" { + +ScannerPlugin hppScanner = +{ + "include_scanner", + "hpp", + openScanner, + closeScanner, + next, + additionalFileTags +}; + +ScannerPlugin cppScanner = +{ + "include_scanner", + "cpp", + openScanner, + closeScanner, + next, + additionalFileTags +}; + +ScannerPlugin *theScanners[3] = {&hppScanner, &cppScanner, NULL}; + +CPPSCANNER_EXPORT ScannerPlugin **getScanners() +{ + return theScanners; +} + +} // extern "C" diff --git a/src/plugins/scanner/cpp/cpp.pro b/src/plugins/scanner/cpp/cpp.pro new file mode 100644 index 000000000..e5d4d8381 --- /dev/null +++ b/src/plugins/scanner/cpp/cpp.pro @@ -0,0 +1,15 @@ +DEFINES += CPLUSPLUS_NO_PARSER + +DESTDIR= ../../../../plugins/ +TEMPLATE = lib +TARGET = qbs_cpp_scanner +DEPENDPATH += . +INCLUDEPATH += . + +QT = core + +unix: CONFIG += plugin + +HEADERS += CPlusPlusForwardDeclarations.h Lexer.h Token.h ../scanner.h \ + cpp_global.h +SOURCES += cpp.cpp Lexer.cpp Token.cpp diff --git a/src/plugins/scanner/cpp/cpp_global.h b/src/plugins/scanner/cpp/cpp_global.h new file mode 100644 index 000000000..1e57911dd --- /dev/null +++ b/src/plugins/scanner/cpp/cpp_global.h @@ -0,0 +1,47 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ + +#ifndef CPP_GLOBAL_H +#define CPP_GLOBAL_H + +#if defined(WIN32) || defined(_WIN32) +#define CPPSCANNER_EXPORT __declspec(dllexport) +#else +#define CPPSCANNER_EXPORT +#endif + +#endif // CPP_GLOBAL_H diff --git a/src/plugins/scanner/qt/qt.cpp b/src/plugins/scanner/qt/qt.cpp new file mode 100644 index 000000000..66d59e59a --- /dev/null +++ b/src/plugins/scanner/qt/qt.cpp @@ -0,0 +1,227 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ + +#if defined(WIN32) || defined(_WIN32) +#define SCANNER_EXPORT __declspec(dllexport) +#else +#define SCANNER_EXPORT +#endif + +#include "../scanner.h" + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_UNIX +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <unistd.h> +#else +#include <QtCore/QFile> +#endif + +#include <QtCore/QString> +#include <QtCore/QXmlStreamReader> +#include <QtCore/QScopedPointer> + + +#include <QDebug> + +struct Opaq +{ +#ifdef Q_OS_UNIX + int fd; + int mapl; +#else + QFile *file; +#endif + + char *map; + QXmlStreamReader *xml; + QByteArray current; + Opaq() +#ifdef Q_OS_UNIX + : fd (0), +#else + : file(0), +#endif + map(0), + xml(0) + {} + + ~Opaq() + { +#ifdef Q_OS_UNIX + if (map) + munmap (map, mapl); + if (fd) + close (fd); +#else + delete file; +#endif + delete xml; + } +}; + +static void *openScanner(const unsigned short *filePath, char **fileTags, int numFileTags) +{ + Q_UNUSED(fileTags); + Q_UNUSED(numFileTags); + QScopedPointer<Opaq> opaque(new Opaq); + +#ifdef Q_OS_UNIX + QString filePathS = QString::fromUtf16(filePath); + opaque->fd = open(qPrintable(filePathS), O_RDONLY); + if (opaque->fd == -1) { + opaque->fd = 0; + return 0; + } + + struct stat s; + int r = fstat(opaque->fd, &s); + if (r != 0) + return 0; + opaque->mapl = s.st_size; + + void *map = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, opaque->fd, 0); + if (map == 0) + return 0; +#else + opaque->file = new QFile(QString::fromUtf16(filePath)); + if (!opaque->file->open(QFile::ReadOnly)) + return 0; + + uchar *map = opaque->file->map(0, opaque->file->size()); + if (!map) + return 0; +#endif + + opaque->map = reinterpret_cast<char *>(map); + opaque->xml = new QXmlStreamReader(opaque->map); + + return static_cast<void *>(opaque.take()); +} + +static void closeScanner(void *ptr) +{ + Opaq *opaque = static_cast<Opaq *>(ptr); + delete opaque; +} + +static const char *nextUi(void *opaq, int *size, int *flags) +{ + Opaq *o= static_cast<Opaq *>(opaq); + while (!o->xml->atEnd()) { + o->xml->readNext(); + switch (o->xml->tokenType()) { + case QXmlStreamReader::StartElement: + if ( o->xml->name() == "include") { + o->current = o->xml->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).toUtf8(); + *flags = SC_GLOBAL_INCLUDE_FLAG; + *size = o->current.size(); + return o->current.data(); + } + break; + case QXmlStreamReader::EndDocument: + return 0; + default: + break; + } + } + return 0; +} + +static const char *nextQrc(void *opaq, int *size, int *flags) +{ + Opaq *o= static_cast<Opaq *>(opaq); + while (!o->xml->atEnd()) { + o->xml->readNext(); + switch (o->xml->tokenType()) { + case QXmlStreamReader::StartElement: + if ( o->xml->name() == "file") { + o->current = o->xml->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).toUtf8(); + *flags = SC_LOCAL_INCLUDE_FLAG; + *size = o->current.size(); + return o->current.data(); + } + break; + case QXmlStreamReader::EndDocument: + return 0; + default: + break; + } + } + return 0; +} + +static const char **additionalFileTags(void *, int *size) +{ + *size = 0; + return 0; +} + +extern "C" { + +ScannerPlugin uiScanner = +{ + "qt_ui_scanner", + "ui", + openScanner, + closeScanner, + nextUi, + additionalFileTags +}; + +ScannerPlugin qrcScanner = +{ + "qt_qrc_scanner", + "qrc", + openScanner, + closeScanner, + nextQrc, + additionalFileTags +}; + +ScannerPlugin *theScanners[3] = {&uiScanner, &qrcScanner, NULL}; + +SCANNER_EXPORT ScannerPlugin **getScanners() +{ + return theScanners; +} + +} // extern "C" diff --git a/src/plugins/scanner/qt/qt.pro b/src/plugins/scanner/qt/qt.pro new file mode 100644 index 000000000..c825e9d15 --- /dev/null +++ b/src/plugins/scanner/qt/qt.pro @@ -0,0 +1,12 @@ +DESTDIR= ../../../../plugins +TEMPLATE = lib +TARGET = qbs_qt_scanner +DEPENDPATH += . +INCLUDEPATH += . + +Qt = core xml + +unix: CONFIG += plugin + +HEADERS += ../scanner.h +SOURCES += qt.cpp diff --git a/src/plugins/scanner/scanner.h b/src/plugins/scanner/scanner.h new file mode 100644 index 000000000..402112d8e --- /dev/null +++ b/src/plugins/scanner/scanner.h @@ -0,0 +1,93 @@ +/************************************************************************** +** +** This file is part of the Qt Build Suite +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. +** Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +**************************************************************************/ +#ifndef SCANNER_H +#define SCANNER_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define SC_LOCAL_INCLUDE_FLAG 0x1 +#define SC_GLOBAL_INCLUDE_FLAG 0x2 + +/** + * Open a file that's going to be scanned. + * The file path encoding is UTF-16 on all platforms. + * + * If the scanner is used for more than one type hint (e.g. C++ header / source) + * the scanner can read the parameter fileTag which file type it is going to scan. + * + * Returns a scanner handle. + */ +typedef void *(*scanOpen_f) (const unsigned short *filePath, char **fileTags, int numFileTags); + +/** + * Closes the given scanner handle. + */ +typedef void (*scanClose_f) (void *opaq); + +/** + * Return the next result (filename) of the scan. + */ +typedef const char *(*scanNext_f) (void *opaq, int *size, int *flags); + +/** + * Returns a list of type hints for the scanned file. + * May return null. + * + * Example: if a C++ header file contains Q_OBJECT, + * the type hint 'moc_hpp' is returned. + */ +typedef const char** (*scanAdditionalFileTags_f) (void *opaq, int *size); + +struct ScannerPlugin +{ + const char *name; + const char *fileTag; + scanOpen_f open; + scanClose_f close; + scanNext_f next; + scanAdditionalFileTags_f additionalFileTags; +}; + +typedef ScannerPlugin **(*getScanners_f)(); + +#ifdef __cplusplus +} +#endif +#endif // SCANNER_H diff --git a/src/plugins/scanner/scanner.pro b/src/plugins/scanner/scanner.pro new file mode 100644 index 000000000..68acae7da --- /dev/null +++ b/src/plugins/scanner/scanner.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = cpp qt + |