Clang: Introduce Token class to work with CXToken pointers

Make tokenization and tokens annotation simpler.

Task-number: QTCREATORBUG-21143
Task-number: QTCREATORBUG-21144
Change-Id: I580091b7b63dd973228fd2e21cf2e74c7d0e7df2
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-09-24 12:10:19 +02:00
parent aa290912b8
commit 65ea6f8e83
19 changed files with 525 additions and 245 deletions

View File

@@ -53,6 +53,7 @@ HEADERS += \
$$PWD/skippedsourceranges.h \ $$PWD/skippedsourceranges.h \
$$PWD/sourcelocation.h \ $$PWD/sourcelocation.h \
$$PWD/sourcerange.h \ $$PWD/sourcerange.h \
$$PWD/token.h \
$$PWD/tokeninfo.h \ $$PWD/tokeninfo.h \
$$PWD/tokenprocessor.h \ $$PWD/tokenprocessor.h \
$$PWD/tokenprocessoriterator.h \ $$PWD/tokenprocessoriterator.h \
@@ -107,6 +108,7 @@ SOURCES += \
$$PWD/skippedsourceranges.cpp \ $$PWD/skippedsourceranges.cpp \
$$PWD/sourcelocation.cpp \ $$PWD/sourcelocation.cpp \
$$PWD/sourcerange.cpp \ $$PWD/sourcerange.cpp \
$$PWD/token.cpp \
$$PWD/tokeninfo.cpp \ $$PWD/tokeninfo.cpp \
$$PWD/unsavedfile.cpp \ $$PWD/unsavedfile.cpp \
$$PWD/unsavedfiles.cpp \ $$PWD/unsavedfiles.cpp \

View File

@@ -29,6 +29,7 @@
#include "cursor.h" #include "cursor.h"
#include "clangstring.h" #include "clangstring.h"
#include "sourcerange.h" #include "sourcerange.h"
#include "token.h"
#include "clangsupportdebugutils.h" #include "clangsupportdebugutils.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -37,65 +38,35 @@
namespace ClangBackEnd { namespace ClangBackEnd {
namespace { static SourceRange getOperatorRange(const Tokens &tokens,
std::vector<Token>::const_iterator currentToken)
struct Tokens
{ {
Tokens(const Tokens &) = delete; const SourceLocation start = currentToken->location();
Tokens(const Cursor &cursor) { currentToken += 2;
tu = cursor.cxTranslationUnit(); while (currentToken != tokens.cend() && !(currentToken->spelling() == "("))
clang_tokenize(tu, cursor.cxSourceRange(), &data, &tokenCount); ++currentToken;
}
Tokens(const CXTranslationUnit &tu) {
const CXSourceRange range
= clang_getCursorExtent(clang_getTranslationUnitCursor(tu));
clang_tokenize(tu, range, &data, &tokenCount);
}
~Tokens() {
clang_disposeTokens(tu, data, tokenCount);
}
CXToken *data = nullptr; return SourceRange(start, currentToken->location());
uint tokenCount = 0;
private:
CXTranslationUnit tu;
};
} // anonymous namespace
static SourceRange getOperatorRange(const CXTranslationUnit tu,
const Tokens &tokens,
uint operatorIndex)
{
const CXSourceLocation start = clang_getTokenLocation(tu, tokens.data[operatorIndex]);
operatorIndex += 2;
while (operatorIndex < tokens.tokenCount
&& !(ClangString(clang_getTokenSpelling(tu, tokens.data[operatorIndex])) == "(")) {
++operatorIndex;
}
const CXSourceLocation end = clang_getTokenLocation(tu, tokens.data[operatorIndex]);
return SourceRange(tu, clang_getRange(start, end));
} }
static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor, static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor,
const Utf8String &tokenStr) const Utf8String &tokenStr)
{ {
Tokens tokens(cursor); Tokens tokens(cursor.sourceRange());
const CXTranslationUnit tu = cursor.cxTranslationUnit(); for (auto it = tokens.cbegin(); it != tokens.cend(); ++it) {
for (uint i = 0; i < tokens.tokenCount; ++i) { const Token &currentToken = *it;
if (!(tokenStr == ClangString(clang_getTokenSpelling(tu, tokens.data[i])))) if (!(tokenStr == currentToken.spelling()))
continue; continue;
if (cursor.isFunctionLike() || cursor.isConstructorOrDestructor()) { if (cursor.isFunctionLike() || cursor.isConstructorOrDestructor()) {
if (tokenStr == "operator") if (tokenStr == "operator")
return getOperatorRange(tu, tokens, i); return getOperatorRange(tokens, it);
if (i+1 > tokens.tokenCount auto nextIt = it + 1;
|| !(ClangString(clang_getTokenSpelling(tu, tokens.data[i+1])) == "(")) { if (nextIt == tokens.cend() || !(nextIt->spelling() == "("))
continue; continue;
} }
} return currentToken.extent();
return SourceRange(tu, clang_getTokenExtent(tu, tokens.data[i]));
} }
return SourceRangeContainer(); return SourceRangeContainer();
} }
@@ -103,8 +74,8 @@ static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor,
static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line, uint column) static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line, uint column)
{ {
int tokenIndex = -1; int tokenIndex = -1;
for (int i = static_cast<int>(tokens.tokenCount - 1); i >= 0; --i) { for (int i = static_cast<int>(tokens.size() - 1); i >= 0; --i) {
const SourceRange range(tu, clang_getTokenExtent(tu, tokens.data[i])); const SourceRange range(tu, tokens[i].extent());
if (range.contains(line, column)) { if (range.contains(line, column)) {
tokenIndex = i; tokenIndex = i;
break; break;
@@ -118,28 +89,28 @@ FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu,
uint line, uint line,
uint column) uint column)
{ {
std::unique_ptr<Tokens> tokens(new Tokens(fullCursor)); Tokens tokens(fullCursor.sourceRange());
if (!tokens->tokenCount) if (!tokens.size()) {
tokens.reset(new Tokens(tu)); const Cursor tuCursor(clang_getTranslationUnitCursor(tu));
tokens = Tokens(tuCursor.sourceRange());
}
if (!tokens->tokenCount) if (!tokens.size())
return SourceRangeContainer(); return SourceRangeContainer();
QVector<CXCursor> cursors(static_cast<int>(tokens->tokenCount)); std::vector<Cursor> cursors = tokens.annotate();
clang_annotateTokens(tu, tokens->data, tokens->tokenCount, cursors.data()); int tokenIndex = getTokenIndex(tu, tokens, line, column);
int tokenIndex = getTokenIndex(tu, *tokens, line, column);
QTC_ASSERT(tokenIndex >= 0, return SourceRangeContainer()); QTC_ASSERT(tokenIndex >= 0, return SourceRangeContainer());
const Utf8String tokenSpelling = ClangString( const Utf8String tokenSpelling = tokens[tokenIndex].spelling();
clang_getTokenSpelling(tu, tokens->data[tokenIndex]));
if (tokenSpelling.isEmpty()) if (tokenSpelling.isEmpty())
return SourceRangeContainer(); return SourceRangeContainer();
Cursor cursor{cursors[tokenIndex]}; Cursor cursor{cursors[tokenIndex]};
if (cursor.kind() == CXCursor_InclusionDirective) { if (cursor.kind() == CXCursor_InclusionDirective) {
CXFile file = clang_getIncludedFile(cursors[tokenIndex]); CXFile file = clang_getIncludedFile(cursors[tokenIndex].cx());
const ClangString filename(clang_getFileName(file)); const ClangString filename(clang_getFileName(file));
const SourceLocation loc(tu, filename, 1, 1); const SourceLocation loc(tu, filename, 1, 1);
FollowSymbolResult result; FollowSymbolResult result;

View File

@@ -28,6 +28,7 @@
#include "clangstring.h" #include "clangstring.h"
#include "cursor.h" #include "cursor.h"
#include "sourcerange.h" #include "sourcerange.h"
#include "token.h"
#include <clangsupport/sourcerangecontainer.h> #include <clangsupport/sourcerangecontainer.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -119,52 +120,32 @@ class ReferencesCollector
{ {
public: public:
ReferencesCollector(CXTranslationUnit cxTranslationUnit); ReferencesCollector(CXTranslationUnit cxTranslationUnit);
~ReferencesCollector();
ReferencesResult collect(uint line, uint column, bool localReferences = false) const; ReferencesResult collect(uint line, uint column, bool localReferences = false) const;
private: private:
bool isWithinTokenRange(CXToken token, uint line, uint column) const;
bool pointsToIdentifier(uint line, uint column, unsigned *tokenIndex) const; bool pointsToIdentifier(uint line, uint column, unsigned *tokenIndex) const;
bool matchesIdentifier(const CXToken &token, const Utf8String &identifier) const; bool matchesIdentifier(const Token &token, const Utf8String &identifier) const;
bool checkToken(unsigned index, const Utf8String &identifier, const Utf8String &usr) const; bool checkToken(unsigned index, const Utf8String &identifier, const Utf8String &usr) const;
private: private:
CXTranslationUnit m_cxTranslationUnit = nullptr; CXTranslationUnit m_cxTranslationUnit = nullptr;
CXToken *m_cxTokens = nullptr; Tokens m_tokens;
uint m_cxTokenCount = 0; std::vector<Cursor> m_cursors;
QVector<CXCursor> m_cxCursors;
}; };
ReferencesCollector::ReferencesCollector(CXTranslationUnit cxTranslationUnit) ReferencesCollector::ReferencesCollector(CXTranslationUnit cxTranslationUnit)
: m_cxTranslationUnit(cxTranslationUnit) : m_cxTranslationUnit(cxTranslationUnit)
, m_tokens(Cursor(clang_getTranslationUnitCursor(m_cxTranslationUnit)).sourceRange())
, m_cursors(m_tokens.annotate())
{ {
const CXSourceRange range
= clang_getCursorExtent(clang_getTranslationUnitCursor(m_cxTranslationUnit));
clang_tokenize(cxTranslationUnit, range, &m_cxTokens, &m_cxTokenCount);
m_cxCursors.resize(static_cast<int>(m_cxTokenCount));
clang_annotateTokens(cxTranslationUnit, m_cxTokens, m_cxTokenCount, m_cxCursors.data());
}
ReferencesCollector::~ReferencesCollector()
{
clang_disposeTokens(m_cxTranslationUnit, m_cxTokens, m_cxTokenCount);
}
bool ReferencesCollector::isWithinTokenRange(CXToken token, uint line, uint column) const
{
const SourceRange range {m_cxTranslationUnit, clang_getTokenExtent(m_cxTranslationUnit, token)};
return range.contains(line, column);
} }
bool ReferencesCollector::pointsToIdentifier(uint line, uint column, unsigned *tokenIndex) const bool ReferencesCollector::pointsToIdentifier(uint line, uint column, unsigned *tokenIndex) const
{ {
for (uint i = 0; i < m_cxTokenCount; ++i) { for (uint i = 0; i < m_tokens.size(); ++i) {
const CXToken token = m_cxTokens[i]; const Token &token = m_tokens[i];
if (clang_getTokenKind(token) == CXToken_Identifier if (token.kind() == CXToken_Identifier && token.extent().contains(line, column)) {
&& isWithinTokenRange(token, line, column)) {
*tokenIndex = i; *tokenIndex = i;
return true; return true;
} }
@@ -173,15 +154,12 @@ bool ReferencesCollector::pointsToIdentifier(uint line, uint column, unsigned *t
return false; return false;
} }
bool ReferencesCollector::matchesIdentifier(const CXToken &token, bool ReferencesCollector::matchesIdentifier(const Token &token,
const Utf8String &identifier) const const Utf8String &identifier) const
{ {
const CXTokenKind tokenKind = clang_getTokenKind(token); const CXTokenKind tokenKind = token.kind();
if (tokenKind == CXToken_Identifier) { if (tokenKind == CXToken_Identifier)
const Utf8String candidateIdentifier return token.spelling() == identifier;
= ClangString(clang_getTokenSpelling(m_cxTranslationUnit, token));
return candidateIdentifier == identifier;
}
return false; return false;
} }
@@ -189,7 +167,7 @@ bool ReferencesCollector::matchesIdentifier(const CXToken &token,
bool ReferencesCollector::checkToken(unsigned index, const Utf8String &identifier, bool ReferencesCollector::checkToken(unsigned index, const Utf8String &identifier,
const Utf8String &usr) const const Utf8String &usr) const
{ {
const CXToken token = m_cxTokens[index]; const Token &token = m_tokens[index];
if (!matchesIdentifier(token, identifier)) if (!matchesIdentifier(token, identifier))
return false; return false;
@@ -201,8 +179,7 @@ bool ReferencesCollector::checkToken(unsigned index, const Utf8String &identifie
// qWarning() << "ReferencesCollector::checkToken:" << line << spelling; // qWarning() << "ReferencesCollector::checkToken:" << line << spelling;
} }
const Cursor currentCursor(m_cxCursors[static_cast<int>(index)]); const ReferencedCursor candidate = ReferencedCursor::find(m_cursors[index]);
const ReferencedCursor candidate = ReferencedCursor::find(currentCursor);
return candidate.usr() == usr; return candidate.usr() == usr;
} }
@@ -215,9 +192,7 @@ ReferencesResult ReferencesCollector::collect(uint line, uint column, bool local
if (!pointsToIdentifier(line, column, &index)) if (!pointsToIdentifier(line, column, &index))
return result; return result;
const Cursor cursorFromUser = m_cxCursors[static_cast<int>(index)]; const ReferencedCursor refCursor = ReferencedCursor::find(m_cursors[index]);
const ReferencedCursor refCursor = ReferencedCursor::find(cursorFromUser);
const Utf8String usr = refCursor.usr(); const Utf8String usr = refCursor.usr();
if (usr.isEmpty()) if (usr.isEmpty())
return result; return result;
@@ -225,14 +200,11 @@ ReferencesResult ReferencesCollector::collect(uint line, uint column, bool local
if (localReferences && !refCursor.isLocalVariable()) if (localReferences && !refCursor.isLocalVariable())
return result; return result;
const CXToken token = m_cxTokens[index]; const Token &token = m_tokens[index];
const Utf8String identifier = ClangString(clang_getTokenSpelling(m_cxTranslationUnit, token)); const Utf8String identifier = token.spelling();
for (uint i = 0; i < m_cxTokenCount; ++i) { for (uint i = 0; i < m_tokens.size(); ++i) {
if (checkToken(i, identifier, usr)) { if (checkToken(i, identifier, usr))
const SourceRange range {m_cxTranslationUnit, result.references.append(m_tokens[i].extent());
clang_getTokenExtent(m_cxTranslationUnit, m_cxTokens[i])};
result.references.append(range);
}
} }
result.isLocalVariable = refCursor.isLocalVariable(); result.isLocalVariable = refCursor.isLocalVariable();

View File

@@ -29,6 +29,7 @@
#include "clangstring.h" #include "clangstring.h"
#include "cursor.h" #include "cursor.h"
#include "sourcerange.h" #include "sourcerange.h"
#include "token.h"
#include "unsavedfiles.h" #include "unsavedfiles.h"
#include "unsavedfile.h" #include "unsavedfile.h"
@@ -275,17 +276,12 @@ Utf8String ToolTipInfoCollector::textForNamespaceAlias(const Cursor &cursor) con
{ {
// TODO: Add some libclang API to get the aliased name straight away. // TODO: Add some libclang API to get the aliased name straight away.
CXToken *cxTokens = nullptr; const Tokens tokens(cursor.sourceRange());
uint cxTokenCount = 0;
clang_tokenize(m_cxTranslationUnit, cursor.cxSourceRange(), &cxTokens, &cxTokenCount);
Utf8String aliasedName; Utf8String aliasedName;
// Start at 3 in order to skip these tokens: namespace X = // Start at 3 in order to skip these tokens: namespace X =
for (uint i = 3; i < cxTokenCount; ++i) for (uint i = 3; i < tokens.size(); ++i)
aliasedName += ClangString(clang_getTokenSpelling(m_cxTranslationUnit, cxTokens[i])); aliasedName += tokens[i].spelling();
clang_disposeTokens(m_cxTranslationUnit, cxTokens, cxTokenCount);
return aliasedName; return aliasedName;
} }

View File

@@ -197,7 +197,7 @@ TokenProcessor<TokenInfo> TranslationUnit::tokenInfos() const
TokenProcessor<TokenInfo> TranslationUnit::tokenInfosInRange(const SourceRange &range) const TokenProcessor<TokenInfo> TranslationUnit::tokenInfosInRange(const SourceRange &range) const
{ {
return TokenProcessor<TokenInfo>(m_cxTranslationUnit, range); return TokenProcessor<TokenInfo>(range);
} }
TokenProcessor<FullTokenInfo> TranslationUnit::fullTokenInfos() const TokenProcessor<FullTokenInfo> TranslationUnit::fullTokenInfos() const
@@ -207,7 +207,7 @@ TokenProcessor<FullTokenInfo> TranslationUnit::fullTokenInfos() const
TokenProcessor<FullTokenInfo> TranslationUnit::fullTokenInfosInRange(const SourceRange &range) const TokenProcessor<FullTokenInfo> TranslationUnit::fullTokenInfosInRange(const SourceRange &range) const
{ {
return TokenProcessor<FullTokenInfo>(m_cxTranslationUnit, range); return TokenProcessor<FullTokenInfo>(range);
} }
SkippedSourceRanges TranslationUnit::skippedSourceRanges() const SkippedSourceRanges TranslationUnit::skippedSourceRanges() const

View File

@@ -35,8 +35,6 @@
#include <vector> #include <vector>
class Utf8String;
namespace ClangBackEnd { namespace ClangBackEnd {
class SourceLocation; class SourceLocation;

View File

@@ -28,17 +28,17 @@
#include "cursor.h" #include "cursor.h"
#include "fulltokeninfo.h" #include "fulltokeninfo.h"
#include "sourcerange.h" #include "sourcerange.h"
#include "token.h"
#include "tokenprocessor.h" #include "tokenprocessor.h"
#include <utils/predicates.h> #include <utils/predicates.h>
namespace ClangBackEnd { namespace ClangBackEnd {
FullTokenInfo::FullTokenInfo(const CXCursor &cxCursor, FullTokenInfo::FullTokenInfo(const Cursor &cursor,
CXToken *cxToken, const Token *token,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &currentOutputArgumentRanges) std::vector<CXSourceRange> &currentOutputArgumentRanges)
: TokenInfo(cxCursor, cxToken, cxTranslationUnit, currentOutputArgumentRanges) : TokenInfo(cursor, token, currentOutputArgumentRanges)
{ {
} }
@@ -101,15 +101,13 @@ static Utf8String propertyParentSpelling(CXTranslationUnit cxTranslationUnit,
return parentSpelling; return parentSpelling;
} }
static Utf8String getPropertyType(const CXSourceLocation &cxLocation, static Utf8String getPropertyType(const SourceLocation &location, uint propertyPosition)
CXTranslationUnit cxTranslationUnit,
uint propertyPosition)
{ {
// Extract property type from the source code // Extract property type from the source code
CXFile cxFile; CXFile cxFile;
uint offset; uint offset;
clang_getFileLocation(cxLocation, &cxFile, nullptr, nullptr, &offset); clang_getFileLocation(location.cx(), &cxFile, nullptr, nullptr, &offset);
const char *const contents = clang_getFileContents(cxTranslationUnit, cxFile, nullptr); const char *const contents = clang_getFileContents(location.tu(), cxFile, nullptr);
const char *const lineContents = &contents[offset - propertyPosition]; const char *const lineContents = &contents[offset - propertyPosition];
const char *typeStart = std::strstr(lineContents, "Q_PROPERTY") + 10; const char *typeStart = std::strstr(lineContents, "Q_PROPERTY") + 10;
@@ -125,18 +123,15 @@ static Utf8String getPropertyType(const CXSourceLocation &cxLocation,
void FullTokenInfo::updatePropertyData() void FullTokenInfo::updatePropertyData()
{ {
CXSourceRange cxRange(clang_getTokenExtent(m_cxTranslationUnit, *m_cxToken)); const SourceRange range = m_token->extent();
const SourceRange range(m_cxTranslationUnit, cxRange); m_extraInfo.semanticParentTypeSpelling = propertyParentSpelling(m_token->tu(),
m_extraInfo.semanticParentTypeSpelling = propertyParentSpelling(m_cxTranslationUnit,
range.start().filePath(), range.start().filePath(),
line(), line(),
column()); column());
m_extraInfo.cursorRange = range; m_extraInfo.cursorRange = range;
m_extraInfo.declaration = true; m_extraInfo.declaration = true;
m_extraInfo.definition = true; m_extraInfo.definition = true;
m_extraInfo.typeSpelling = getPropertyType(clang_getRangeStart(cxRange), m_extraInfo.typeSpelling = getPropertyType(range.start(), column() - 1);
m_cxTranslationUnit,
column() - 1);
} }
void FullTokenInfo::identifierKind(const Cursor &cursor, Recursion recursion) void FullTokenInfo::identifierKind(const Cursor &cursor, Recursion recursion)
@@ -263,9 +258,8 @@ void FullTokenInfo::overloadedOperatorKind()
void FullTokenInfo::evaluate() void FullTokenInfo::evaluate()
{ {
m_extraInfo.token = ClangString(clang_getTokenSpelling(m_cxTranslationUnit, *m_cxToken)); m_extraInfo.token = m_token->spelling();
CXTokenKind cxTokenKind = m_token->kind();
auto cxTokenKind = clang_getTokenKind(*m_cxToken);
if (cxTokenKind == CXToken_Identifier) { if (cxTokenKind == CXToken_Identifier) {
m_extraInfo.declaration = m_originalCursor.isDeclaration(); m_extraInfo.declaration = m_originalCursor.isDeclaration();
m_extraInfo.definition = m_originalCursor.isDefinition(); m_extraInfo.definition = m_originalCursor.isDefinition();

View File

@@ -34,9 +34,8 @@ class FullTokenInfo : public TokenInfo
template<class T> friend class TokenProcessor; template<class T> friend class TokenProcessor;
public: public:
FullTokenInfo() = default; FullTokenInfo() = default;
FullTokenInfo(const CXCursor &cxCursor, FullTokenInfo(const Cursor &cursor,
CXToken *cxToken, const Token *token,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &m_currentOutputArgumentRanges); std::vector<CXSourceRange> &m_currentOutputArgumentRanges);
void evaluate() override; void evaluate() override;

View File

@@ -64,6 +64,9 @@ public:
SourceLocationContainer toSourceLocationContainer() const; SourceLocationContainer toSourceLocationContainer() const;
CXTranslationUnit tu() const { return cxTranslationUnit; }
CXSourceLocation cx() const { return cxSourceLocation; }
private: private:
operator CXSourceLocation() const; operator CXSourceLocation() const;

View File

@@ -56,6 +56,8 @@ public:
operator CXSourceRange() const; operator CXSourceRange() const;
operator SourceRangeContainer() const; operator SourceRangeContainer() const;
CXTranslationUnit tu() const { return cxTranslationUnit; }
private: private:
CXSourceRange cxSourceRange; CXSourceRange cxSourceRange;
CXTranslationUnit cxTranslationUnit = nullptr; CXTranslationUnit cxTranslationUnit = nullptr;

View File

@@ -0,0 +1,141 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "token.h"
#include "clangstring.h"
#include "cursor.h"
#include "sourcelocation.h"
#include "sourcerange.h"
namespace ClangBackEnd {
Token::Token(CXTranslationUnit cxTranslationUnit, CXToken *cxToken)
: m_cxTranslationUnit(cxTranslationUnit)
, m_cxToken(cxToken)
{
}
bool Token::isNull() const
{
return !m_cxToken;
}
CXTokenKind Token::kind() const
{
return clang_getTokenKind(*m_cxToken);
}
CXToken *Token::cx() const
{
return m_cxToken;
}
SourceLocation Token::location() const
{
return SourceLocation(m_cxTranslationUnit, clang_getTokenLocation(m_cxTranslationUnit, *m_cxToken));
}
SourceRange Token::extent() const
{
return SourceRange(m_cxTranslationUnit, clang_getTokenExtent(m_cxTranslationUnit, *m_cxToken));
}
ClangString Token::spelling() const
{
return clang_getTokenSpelling(m_cxTranslationUnit, *m_cxToken);
}
Tokens::Tokens(const SourceRange &range)
: m_cxTranslationUnit(range.tu())
{
CXSourceRange cxRange(range);
CXToken *cxTokens;
unsigned numTokens;
clang_tokenize(m_cxTranslationUnit, cxRange, &cxTokens, &numTokens);
m_tokens.reserve(numTokens);
for (size_t i = 0; i < numTokens; ++i)
m_tokens.push_back(Token(m_cxTranslationUnit, cxTokens + i));
}
std::vector<Cursor> Tokens::annotate() const
{
std::vector<Cursor> cursors;
if (m_tokens.empty())
return cursors;
std::vector<CXCursor> cxCursors;
cxCursors.resize(m_tokens.size());
clang_annotateTokens(m_cxTranslationUnit, m_tokens.front().cx(),
static_cast<unsigned>(m_tokens.size()), cxCursors.data());
cursors.reserve(cxCursors.size());
for (const CXCursor &cxCursor : cxCursors)
cursors.emplace_back(cxCursor);
return cursors;
}
const Token &Tokens::operator[](size_t index) const
{
return m_tokens[index];
}
Token &Tokens::operator[](size_t index)
{
return m_tokens[index];
}
std::vector<Token>::const_iterator Tokens::cbegin() const
{
return m_tokens.cbegin();
}
std::vector<Token>::const_iterator Tokens::cend() const
{
return m_tokens.cend();
}
std::vector<Token>::iterator Tokens::begin()
{
return m_tokens.begin();
}
std::vector<Token>::iterator Tokens::end()
{
return m_tokens.end();
}
Tokens::~Tokens()
{
if (m_tokens.empty())
return;
clang_disposeTokens(m_cxTranslationUnit, m_tokens.front().cx(),
static_cast<unsigned>(m_tokens.size()));
}
} // namespace ClangBackEnd

View File

@@ -0,0 +1,90 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <clang-c/Index.h>
#include <vector>
namespace ClangBackEnd {
class ClangString;
class Cursor;
class SourceLocation;
class SourceRange;
class Token
{
friend class Tokens;
public:
bool isNull() const;
CXTokenKind kind() const;
SourceLocation location() const;
SourceRange extent() const;
ClangString spelling() const;
CXToken *cx() const;
CXTranslationUnit tu() const { return m_cxTranslationUnit; }
private:
Token(CXTranslationUnit m_cxTranslationUnit, CXToken *cxToken);
CXTranslationUnit m_cxTranslationUnit;
CXToken *m_cxToken;
};
class Tokens
{
public:
Tokens() = default;
Tokens(const SourceRange &range);
~Tokens();
Tokens(Tokens &&other) = default;
Tokens(const Tokens &other) = delete;
Tokens &operator=(Tokens &&other) = default;
Tokens &operator=(const Tokens &other) = delete;
std::vector<Cursor> annotate() const;
size_t size() const { return m_tokens.size(); }
const Token &operator[](size_t index) const;
Token &operator[](size_t index);
std::vector<Token>::const_iterator cbegin() const;
std::vector<Token>::const_iterator cend() const;
std::vector<Token>::iterator begin();
std::vector<Token>::iterator end();
CXTranslationUnit tu() const { return m_cxTranslationUnit; }
private:
CXTranslationUnit m_cxTranslationUnit;
std::vector<Token> m_tokens;
};
} // namespace ClangBackEnd

View File

@@ -25,6 +25,7 @@
#include "clangstring.h" #include "clangstring.h"
#include "cursor.h" #include "cursor.h"
#include "token.h"
#include "tokeninfo.h" #include "tokeninfo.h"
#include "sourcelocation.h" #include "sourcelocation.h"
#include "sourcerange.h" #include "sourcerange.h"
@@ -34,17 +35,14 @@
namespace ClangBackEnd { namespace ClangBackEnd {
TokenInfo::TokenInfo(const CXCursor &cxCursor, TokenInfo::TokenInfo(const Cursor &cursor,
CXToken *cxToken, const Token *token,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &currentOutputArgumentRanges) std::vector<CXSourceRange> &currentOutputArgumentRanges)
: m_originalCursor(cxCursor), : m_originalCursor(cursor),
m_cxToken(cxToken), m_token(token),
m_cxTranslationUnit(cxTranslationUnit),
m_currentOutputArgumentRanges(&currentOutputArgumentRanges) m_currentOutputArgumentRanges(&currentOutputArgumentRanges)
{ {
const SourceRange sourceRange {cxTranslationUnit, const SourceRange sourceRange = token->extent();
clang_getTokenExtent(cxTranslationUnit, *cxToken)};
const auto start = sourceRange.start(); const auto start = sourceRange.start();
const auto end = sourceRange.end(); const auto end = sourceRange.end();
@@ -472,18 +470,18 @@ static HighlightingType literalKind(const Cursor &cursor)
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
static bool isTokenPartOfOperator(const Cursor &declarationCursor, CXToken *token) static bool isTokenPartOfOperator(const Cursor &declarationCursor, const Token &token)
{ {
Q_ASSERT(declarationCursor.isDeclaration()); Q_ASSERT(declarationCursor.isDeclaration());
const CXTranslationUnit cxTranslationUnit = declarationCursor.cxTranslationUnit(); const CXTranslationUnit cxTranslationUnit = declarationCursor.cxTranslationUnit();
const ClangString tokenName = clang_getTokenSpelling(cxTranslationUnit, *token); const ClangString tokenName = token.spelling();
if (tokenName == "operator") if (tokenName == "operator")
return true; return true;
if (tokenName == "(") { if (tokenName == "(") {
// Valid operator declarations have at least one token after '(' so // Valid operator declarations have at least one token after '(' so
// it's safe to proceed to token + 1 without extra checks. // it's safe to proceed to token + 1 without extra checks.
const ClangString nextToken = clang_getTokenSpelling(cxTranslationUnit, *(token + 1)); const ClangString nextToken = clang_getTokenSpelling(cxTranslationUnit, *(token.cx() + 1));
if (nextToken != ")") { if (nextToken != ")") {
// Argument lists' parentheses are not operator tokens. // Argument lists' parentheses are not operator tokens.
// This '('-token opens a (non-empty) argument list. // This '('-token opens a (non-empty) argument list.
@@ -493,7 +491,7 @@ static bool isTokenPartOfOperator(const Cursor &declarationCursor, CXToken *toke
// It's safe to evaluate the preceding token because we will at least have // It's safe to evaluate the preceding token because we will at least have
// the 'operator'-keyword's token to the left. // the 'operator'-keyword's token to the left.
CXToken *prevToken = token - 1; CXToken *prevToken = token.cx() - 1;
if (clang_getTokenKind(*prevToken) == CXToken_Punctuation) { if (clang_getTokenKind(*prevToken) == CXToken_Punctuation) {
if (tokenName == "(") { if (tokenName == "(") {
// In an operator declaration, when a '(' follows another punctuation // In an operator declaration, when a '(' follows another punctuation
@@ -526,7 +524,7 @@ void TokenInfo::overloadedOperatorKind()
if (!declarationCursor.displayName().startsWith("operator")) if (!declarationCursor.displayName().startsWith("operator"))
return; return;
if (inOperatorDeclaration && !isTokenPartOfOperator(declarationCursor, m_cxToken)) if (inOperatorDeclaration && !isTokenPartOfOperator(declarationCursor, *m_token))
return; return;
m_types.mixinHighlightingTypes.push_back(HighlightingType::Operator); m_types.mixinHighlightingTypes.push_back(HighlightingType::Operator);
@@ -580,45 +578,36 @@ enum class QtMacroPart
FunctionOrPrimitiveType FunctionOrPrimitiveType
}; };
static bool isFirstTokenOfCursor(const Cursor &cursor, CXToken *token) static bool isFirstTokenOfCursor(const Cursor &cursor, const Token &token)
{ {
const CXTranslationUnit cxTranslationUnit = cursor.cxTranslationUnit(); return cursor.sourceLocation() == token.location();
const SourceLocation tokenLocation = SourceLocation(cxTranslationUnit,
clang_getTokenLocation(cxTranslationUnit,
*token));
return cursor.sourceLocation() == tokenLocation;
} }
static bool isLastTokenOfCursor(const Cursor &cursor, CXToken *token) static bool isLastTokenOfCursor(const Cursor &cursor, const Token &token)
{ {
const CXTranslationUnit cxTranslationUnit = cursor.cxTranslationUnit(); return cursor.sourceRange().end() == token.location();
const SourceLocation tokenLocation = SourceLocation(cxTranslationUnit,
clang_getTokenLocation(cxTranslationUnit,
*token));
return cursor.sourceRange().end() == tokenLocation;
} }
static bool isValidMacroToken(const Cursor &cursor, CXToken *token) static bool isValidMacroToken(const Cursor &cursor, const Token &token)
{ {
// Proper macro token has at least '(' and ')' around it. // Proper macro token has at least '(' and ')' around it.
return !isFirstTokenOfCursor(cursor, token) && !isLastTokenOfCursor(cursor, token); return !isFirstTokenOfCursor(cursor, token) && !isLastTokenOfCursor(cursor, token);
} }
static QtMacroPart propertyPart(CXTranslationUnit cxTranslationUnit, CXToken *token) static QtMacroPart propertyPart(const Token &token)
{ {
static constexpr const char *propertyKeywords[] static constexpr const char *propertyKeywords[]
= {"READ", "WRITE", "MEMBER", "RESET", "NOTIFY", "REVISION", "DESIGNABLE", = {"READ", "WRITE", "MEMBER", "RESET", "NOTIFY", "REVISION", "DESIGNABLE",
"SCRIPTABLE", "STORED", "USER", "CONSTANT", "FINAL" "SCRIPTABLE", "STORED", "USER", "CONSTANT", "FINAL"
}; };
const ClangString currentToken = clang_getTokenSpelling(cxTranslationUnit, *token); if (std::find(std::begin(propertyKeywords), std::end(propertyKeywords), token.spelling())
if (std::find(std::begin(propertyKeywords), std::end(propertyKeywords), currentToken)
!= std::end(propertyKeywords)) { != std::end(propertyKeywords)) {
return QtMacroPart::Keyword; return QtMacroPart::Keyword;
} }
const ClangString nextToken = clang_getTokenSpelling(cxTranslationUnit, *(token + 1)); const ClangString nextToken = clang_getTokenSpelling(token.tu(), *(token.cx() + 1));
const ClangString previousToken = clang_getTokenSpelling(cxTranslationUnit, *(token - 1)); const ClangString previousToken = clang_getTokenSpelling(token.tu(), *(token.cx() - 1));
if (std::find(std::begin(propertyKeywords), std::end(propertyKeywords), nextToken) if (std::find(std::begin(propertyKeywords), std::end(propertyKeywords), nextToken)
!= std::end(propertyKeywords)) { != std::end(propertyKeywords)) {
if (std::find(std::begin(propertyKeywords), std::end(propertyKeywords), previousToken) if (std::find(std::begin(propertyKeywords), std::end(propertyKeywords), previousToken)
@@ -645,30 +634,30 @@ static QtMacroPart signalSlotPart(CXTranslationUnit cxTranslationUnit, CXToken *
return (prevToken == "SLOT") ? QtMacroPart::SlotFunction : QtMacroPart::SlotType; return (prevToken == "SLOT") ? QtMacroPart::SlotFunction : QtMacroPart::SlotType;
} }
static QtMacroPart qtMacroPart(CXTranslationUnit cxTranslationUnit, CXToken *token) static QtMacroPart qtMacroPart(const Token &token)
{ {
CXSourceLocation location = clang_getTokenLocation(cxTranslationUnit, *token); const SourceLocation location = token.location();
// If current token is inside macro then the cursor from token's position will be // If current token is inside macro then the cursor from token's position will be
// the whole macro cursor. // the whole macro cursor.
Cursor possibleQtMacroCursor = clang_getCursor(cxTranslationUnit, location); Cursor possibleQtMacroCursor = clang_getCursor(token.tu(), location.cx());
if (!isValidMacroToken(possibleQtMacroCursor, token)) if (!isValidMacroToken(possibleQtMacroCursor, token))
return QtMacroPart::None; return QtMacroPart::None;
ClangString spelling = possibleQtMacroCursor.spelling(); ClangString spelling = possibleQtMacroCursor.spelling();
if (spelling == "Q_PROPERTY") if (spelling == "Q_PROPERTY")
return propertyPart(cxTranslationUnit, token); return propertyPart(token);
if (spelling == "SIGNAL") if (spelling == "SIGNAL")
return signalSlotPart(cxTranslationUnit, token, true); return signalSlotPart(token.tu(), token.cx(), true);
if (spelling == "SLOT") if (spelling == "SLOT")
return signalSlotPart(cxTranslationUnit, token, false); return signalSlotPart(token.tu(), token.cx(), false);
return QtMacroPart::None; return QtMacroPart::None;
} }
void TokenInfo::invalidFileKind() void TokenInfo::invalidFileKind()
{ {
const QtMacroPart macroPart = qtMacroPart(m_cxTranslationUnit, m_cxToken); const QtMacroPart macroPart = qtMacroPart(*m_token);
switch (macroPart) { switch (macroPart) {
case QtMacroPart::None: case QtMacroPart::None:
@@ -708,7 +697,7 @@ void TokenInfo::keywordKind()
break; break;
} }
const ClangString spelling = clang_getTokenSpelling(m_cxTranslationUnit, *m_cxToken); const ClangString spelling = m_token->spelling();
if (spelling == "bool" if (spelling == "bool"
|| spelling == "char" || spelling == "char"
|| spelling == "char16_t" || spelling == "char16_t"
@@ -734,7 +723,7 @@ void TokenInfo::keywordKind()
void TokenInfo::evaluate() void TokenInfo::evaluate()
{ {
auto cxTokenKind = clang_getTokenKind(*m_cxToken); auto cxTokenKind = m_token->kind();
m_types = HighlightingTypes(); m_types = HighlightingTypes();

View File

@@ -36,15 +36,17 @@
namespace ClangBackEnd { namespace ClangBackEnd {
class Cursor;
class Token;
class TokenInfo class TokenInfo
{ {
friend bool operator==(const TokenInfo &first, const TokenInfo &second); friend bool operator==(const TokenInfo &first, const TokenInfo &second);
template<class T> friend class TokenProcessor; template<class T> friend class TokenProcessor;
public: public:
TokenInfo() = default; TokenInfo() = default;
TokenInfo(const CXCursor &cxCursor, TokenInfo(const Cursor &cursor,
CXToken *cxToken, const Token *token,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &m_currentOutputArgumentRanges); std::vector<CXSourceRange> &m_currentOutputArgumentRanges);
virtual ~TokenInfo() = default; virtual ~TokenInfo() = default;
@@ -100,8 +102,7 @@ protected:
virtual void punctuationOrOperatorKind(); virtual void punctuationOrOperatorKind();
Cursor m_originalCursor; Cursor m_originalCursor;
CXToken *m_cxToken = nullptr; const Token *m_token;
CXTranslationUnit m_cxTranslationUnit = nullptr;
HighlightingTypes m_types; HighlightingTypes m_types;
private: private:

View File

@@ -27,6 +27,7 @@
#include "fulltokeninfo.h" #include "fulltokeninfo.h"
#include "sourcerange.h" #include "sourcerange.h"
#include "token.h"
#include "tokenprocessoriterator.h" #include "tokenprocessoriterator.h"
#include "tokeninfocontainer.h" #include "tokeninfocontainer.h"
@@ -52,53 +53,43 @@ public:
public: public:
TokenProcessor() = default; TokenProcessor() = default;
TokenProcessor(CXTranslationUnit cxTranslationUnit, const SourceRange &range) TokenProcessor(const SourceRange &range)
: cxTranslationUnit(cxTranslationUnit) : tokens(range)
, cursors(tokens.annotate())
{ {
unsigned cxTokensCount = 0;
clang_tokenize(cxTranslationUnit, range, &cxTokens, &cxTokensCount);
cxCursors.resize(cxTokensCount);
clang_annotateTokens(cxTranslationUnit, cxTokens, cxTokensCount, cxCursors.data());
}
~TokenProcessor()
{
clang_disposeTokens(cxTranslationUnit, cxTokens, unsigned(cxCursors.size()));
} }
bool isEmpty() const bool isEmpty() const
{ {
return cxCursors.empty(); return cursors.empty();
} }
bool isNull() const bool isNull() const
{ {
return cxTokens == nullptr; return !tokens.size();
} }
size_t size() const size_t size() const
{ {
return cxCursors.size(); return cursors.size();
} }
const_iterator begin() const const_iterator begin() const
{ {
return const_iterator(cxCursors.cbegin(), return const_iterator(cursors.cbegin(),
cxTokens, tokens.cbegin(),
cxTranslationUnit,
currentOutputArgumentRanges); currentOutputArgumentRanges);
} }
const_iterator end() const const_iterator end() const
{ {
return const_iterator(cxCursors.cend(), return const_iterator(cursors.cend(),
cxTokens + cxCursors.size(), tokens.cend(),
cxTranslationUnit,
currentOutputArgumentRanges); currentOutputArgumentRanges);
} }
T operator[](size_t index) const T operator[](size_t index) const
{ {
T tokenInfo(cxCursors[index], cxTokens + index, cxTranslationUnit, T tokenInfo(cursors[index], &tokens[index], currentOutputArgumentRanges);
currentOutputArgumentRanges);
tokenInfo.evaluate(); tokenInfo.evaluate();
return tokenInfo; return tokenInfo;
} }
@@ -117,8 +108,8 @@ private:
template<class TC> template<class TC>
QVector<TC> toTokens() const QVector<TC> toTokens() const
{ {
QVector<TC> tokens; QVector<TC> tokenInfos;
tokens.reserve(int(size())); tokenInfos.reserve(int(size()));
const auto isValidTokenInfo = [](const T &tokenInfo) { const auto isValidTokenInfo = [](const T &tokenInfo) {
return !tokenInfo.hasInvalidMainType() return !tokenInfo.hasInvalidMainType()
@@ -126,48 +117,48 @@ private:
&& !tokenInfo.hasMainType(HighlightingType::Comment); && !tokenInfo.hasMainType(HighlightingType::Comment);
}; };
for (size_t index = 0; index < cxCursors.size(); ++index) { for (size_t index = 0; index < cursors.size(); ++index) {
T tokenInfo = (*this)[index]; T tokenInfo = (*this)[index];
if (isValidTokenInfo(tokenInfo)) if (isValidTokenInfo(tokenInfo))
tokens.push_back(tokenInfo); tokenInfos.push_back(tokenInfo);
} }
return tokens; return tokenInfos;
} }
mutable std::vector<CXSourceRange> currentOutputArgumentRanges; mutable std::vector<CXSourceRange> currentOutputArgumentRanges;
CXTranslationUnit cxTranslationUnit = nullptr; Tokens tokens;
CXToken *cxTokens = nullptr; std::vector<Cursor> cursors;
std::vector<CXCursor> cxCursors;
}; };
template <> template <>
inline inline
QVector<TokenInfoContainer> TokenProcessor<FullTokenInfo>::toTokenInfoContainers() const QVector<TokenInfoContainer> TokenProcessor<FullTokenInfo>::toTokenInfoContainers() const
{ {
QVector<FullTokenInfo> tokens = toTokens<FullTokenInfo>(); QVector<FullTokenInfo> tokenInfos = toTokens<FullTokenInfo>();
return Utils::transform(tokens, return Utils::transform(tokenInfos,
[&tokens](FullTokenInfo &token) -> TokenInfoContainer { [&tokenInfos](FullTokenInfo &tokenInfo) -> TokenInfoContainer {
if (!token.m_extraInfo.declaration || token.hasMainType(HighlightingType::LocalVariable)) if (!tokenInfo.m_extraInfo.declaration
return token; || tokenInfo.hasMainType(HighlightingType::LocalVariable)) {
return tokenInfo;
}
const int index = tokens.indexOf(token); const int index = tokenInfos.indexOf(tokenInfo);
const SourceLocationContainer &tokenStart = token.m_extraInfo.cursorRange.start; const SourceLocationContainer &tokenStart = tokenInfo.m_extraInfo.cursorRange.start;
for (auto it = tokens.rend() - index; it != tokens.rend(); ++it) { for (auto it = tokenInfos.rend() - index; it != tokenInfos.rend(); ++it) {
if (it->m_extraInfo.declaration && !it->hasMainType(HighlightingType::LocalVariable) if (it->m_extraInfo.declaration && !it->hasMainType(HighlightingType::LocalVariable)
&& it->m_originalCursor != token.m_originalCursor && it->m_originalCursor != tokenInfo.m_originalCursor
&& it->m_extraInfo.cursorRange.contains(tokenStart)) { && it->m_extraInfo.cursorRange.contains(tokenStart)) {
if (token.m_originalCursor.lexicalParent() != it->m_originalCursor if (tokenInfo.m_originalCursor.lexicalParent() != it->m_originalCursor
&& !token.hasMainType(HighlightingType::QtProperty)) { && !tokenInfo.hasMainType(HighlightingType::QtProperty)) {
continue; continue;
} }
token.m_extraInfo.lexicalParentIndex = std::distance(it, tokens.rend()) - 1; tokenInfo.m_extraInfo.lexicalParentIndex = std::distance(it, tokenInfos.rend()) - 1;
break; break;
} }
} }
return token; return tokenInfo;
}); });
} }

View File

@@ -41,53 +41,49 @@ template<class T>
class TokenProcessorIterator : public std::iterator<std::forward_iterator_tag, TokenInfo, uint> class TokenProcessorIterator : public std::iterator<std::forward_iterator_tag, TokenInfo, uint>
{ {
public: public:
TokenProcessorIterator(std::vector<CXCursor>::const_iterator cxCursorIterator, TokenProcessorIterator(std::vector<Cursor>::const_iterator cursorIterator,
CXToken *cxToken, std::vector<Token>::const_iterator tokenIterator,
CXTranslationUnit cxTranslationUnit,
std::vector<CXSourceRange> &currentOutputArgumentRanges) std::vector<CXSourceRange> &currentOutputArgumentRanges)
: cxCursorIterator(cxCursorIterator), : cursorIterator(cursorIterator),
cxToken(cxToken), tokenIterator(tokenIterator),
cxTranslationUnit(cxTranslationUnit),
currentOutputArgumentRanges(currentOutputArgumentRanges) currentOutputArgumentRanges(currentOutputArgumentRanges)
{} {}
TokenProcessorIterator& operator++() TokenProcessorIterator& operator++()
{ {
++cxCursorIterator; ++cursorIterator;
++cxToken; ++tokenIterator;
return *this; return *this;
} }
TokenProcessorIterator operator++(int) TokenProcessorIterator operator++(int)
{ {
return TokenProcessorIterator(cxCursorIterator++, return TokenProcessorIterator(cursorIterator++,
cxToken++, tokenIterator++,
cxTranslationUnit,
currentOutputArgumentRanges); currentOutputArgumentRanges);
} }
bool operator==(TokenProcessorIterator other) const bool operator==(TokenProcessorIterator other) const
{ {
return cxCursorIterator == other.cxCursorIterator; return cursorIterator == other.cursorIterator;
} }
bool operator!=(TokenProcessorIterator other) const bool operator!=(TokenProcessorIterator other) const
{ {
return cxCursorIterator != other.cxCursorIterator; return cursorIterator != other.cursorIterator;
} }
T operator*() T operator*()
{ {
T tokenInfo(*cxCursorIterator, cxToken, cxTranslationUnit, currentOutputArgumentRanges); T tokenInfo(*cursorIterator, &(*tokenIterator), currentOutputArgumentRanges);
tokenInfo.evaluate(); tokenInfo.evaluate();
return tokenInfo; return tokenInfo;
} }
private: private:
std::vector<CXCursor>::const_iterator cxCursorIterator; std::vector<Cursor>::const_iterator cursorIterator;
CXToken *cxToken; std::vector<Token>::const_iterator tokenIterator;
CXTranslationUnit cxTranslationUnit;
std::vector<CXSourceRange> &currentOutputArgumentRanges; std::vector<CXSourceRange> &currentOutputArgumentRanges;
}; };

View File

@@ -0,0 +1,3 @@
void function(int x)
{
}

View File

@@ -0,0 +1,131 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "googletest.h"
#include "testenvironment.h"
#include <clangdocument.h>
#include <clangdocuments.h>
#include <clangstring.h>
#include <clangtranslationunit.h>
#include <cursor.h>
#include <sourcelocation.h>
#include <sourcerange.h>
#include <token.h>
#include <unsavedfiles.h>
using ClangBackEnd::Cursor;
using ClangBackEnd::Document;
using ClangBackEnd::TranslationUnit;
using ClangBackEnd::UnsavedFiles;
using ClangBackEnd::Documents;
using ClangBackEnd::ClangString;
using ClangBackEnd::SourceLocation;
using ClangBackEnd::SourceRange;
using ClangBackEnd::Token;
using ClangBackEnd::Tokens;
namespace {
struct Data {
ClangBackEnd::UnsavedFiles unsavedFiles;
ClangBackEnd::Documents documents{unsavedFiles};
Utf8String filePath{Utf8StringLiteral(TESTDATA_DIR"/token.cpp")};
Utf8StringVector compilationArguments{
TestEnvironment::addPlatformArguments({Utf8StringLiteral("-std=c++11")})};
Document document{filePath, compilationArguments, documents};
TranslationUnit translationUnit{filePath,
filePath,
document.translationUnit().cxIndex(),
document.translationUnit().cxTranslationUnit()};
};
class Token : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
d = std::make_unique<const Data>();
d->document.parse();
}
protected:
static std::unique_ptr<const Data> d;
const Document &document = d->document;
const TranslationUnit &translationUnit = d->translationUnit;
const SourceRange range{{translationUnit.cxTranslationUnit(), d->filePath, 1, 1},
{translationUnit.cxTranslationUnit(), d->filePath, 3, 2}};
const Tokens tokens{range};
};
std::unique_ptr<const Data> Token::d;
TEST_F(Token, CreateTokens)
{
ASSERT_THAT(tokens.size(), 8u);
}
TEST_F(Token, AnnotateTokens)
{
auto cursors = tokens.annotate();
ASSERT_THAT(cursors.size(), 8u);
}
TEST_F(Token, TokenKind)
{
auto kind = tokens[0].kind();
ASSERT_THAT(kind, CXToken_Keyword);
}
TEST_F(Token, TokenLocation)
{
auto location = range.start();
auto tokenLocation = tokens[0].location();
ASSERT_THAT(tokenLocation, location);
}
TEST_F(Token, TokenSpelling)
{
auto spelling = tokens[0].spelling();
ASSERT_THAT(spelling, "void");
}
TEST_F(Token, TokenExtent)
{
::SourceRange tokenRange(range.start(), ::SourceLocation(translationUnit.cxTranslationUnit(), d->filePath, 1, 5));
auto extent = tokens[0].extent();
ASSERT_THAT(extent, tokenRange);
}
}

View File

@@ -101,7 +101,7 @@ SOURCES += \
refactoringprojectupdater-test.cpp \ refactoringprojectupdater-test.cpp \
projectpartqueue-test.cpp \ projectpartqueue-test.cpp \
processormanager-test.cpp \ processormanager-test.cpp \
taskscheduler-test.cpp taskscheduler-test.cpp \
!isEmpty(LIBCLANG_LIBS) { !isEmpty(LIBCLANG_LIBS) {
SOURCES += \ SOURCES += \
@@ -154,6 +154,7 @@ SOURCES += \
sqlitestatement-test.cpp \ sqlitestatement-test.cpp \
sqlitetable-test.cpp \ sqlitetable-test.cpp \
sqlstatementbuilder-test.cpp \ sqlstatementbuilder-test.cpp \
token-test.cpp \
translationunitupdater-test.cpp \ translationunitupdater-test.cpp \
unsavedfiles-test.cpp \ unsavedfiles-test.cpp \
unsavedfile-test.cpp \ unsavedfile-test.cpp \