forked from qt-creator/qt-creator
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:
@@ -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 \
|
||||||
|
|||||||
@@ -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 ¤tToken = *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 SourceRange(tu, clang_getTokenExtent(tu, tokens.data[i]));
|
return currentToken.extent();
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -35,8 +35,6 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class Utf8String;
|
|
||||||
|
|
||||||
namespace ClangBackEnd {
|
namespace ClangBackEnd {
|
||||||
|
|
||||||
class SourceLocation;
|
class SourceLocation;
|
||||||
|
|||||||
@@ -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> ¤tOutputArgumentRanges)
|
std::vector<CXSourceRange> ¤tOutputArgumentRanges)
|
||||||
: 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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
141
src/tools/clangbackend/source/token.cpp
Normal file
141
src/tools/clangbackend/source/token.cpp
Normal 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
|
||||||
90
src/tools/clangbackend/source/token.h
Normal file
90
src/tools/clangbackend/source/token.h
Normal 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
|
||||||
@@ -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> ¤tOutputArgumentRanges)
|
std::vector<CXSourceRange> ¤tOutputArgumentRanges)
|
||||||
: m_originalCursor(cxCursor),
|
: m_originalCursor(cursor),
|
||||||
m_cxToken(cxToken),
|
m_token(token),
|
||||||
m_cxTranslationUnit(cxTranslationUnit),
|
|
||||||
m_currentOutputArgumentRanges(¤tOutputArgumentRanges)
|
m_currentOutputArgumentRanges(¤tOutputArgumentRanges)
|
||||||
{
|
{
|
||||||
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();
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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> ¤tOutputArgumentRanges)
|
std::vector<CXSourceRange> ¤tOutputArgumentRanges)
|
||||||
: 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> ¤tOutputArgumentRanges;
|
std::vector<CXSourceRange> ¤tOutputArgumentRanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
3
tests/unit/unittest/data/token.cpp
Normal file
3
tests/unit/unittest/data/token.cpp
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
void function(int x)
|
||||||
|
{
|
||||||
|
}
|
||||||
131
tests/unit/unittest/token-test.cpp
Normal file
131
tests/unit/unittest/token-test.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 \
|
||||||
|
|||||||
Reference in New Issue
Block a user