forked from qt-creator/qt-creator
Clang: Provide tooltips
This includes also the query data for the help system (F1) for an
identifier under cursor.
Regressions (libclang changes necessary):
- Function signatures do not contain default values.
- Aliases are not resolved for/at:
- template types
- qualified name of a type
Fixes/Improvements:
- Resolve "auto"
- On a template type, show also the template parameter.
- For a typedef like
typedef long long superlong;
the tooltip was "long long superlong", which was confusing.
Now, "long long" is shown.
New:
- Show first or \brief paragraph of a documentation comment.
- Show size of a class at definition.
- Show size of a field member in class definition.
Task-number: QTCREATORBUG-11259
Change-Id: Ie1a07930d0e882015d07dc43e35bb81a685cdeb8
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -36,4 +36,9 @@ enum class PreferredTranslationUnit
|
||||
LastUninitialized,
|
||||
};
|
||||
|
||||
// CLANG-UPGRADE-CHECK: Remove IS_SUSPEND_SUPPORTED once we require clang >= 7.0
|
||||
#if defined(CINDEX_VERSION_HAS_PRETTYDECL_BACKPORTED) || CINDEX_VERSION_MINOR >= 47
|
||||
# define IS_PRETTY_DECL_SUPPORTED
|
||||
#endif
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -29,10 +29,12 @@ HEADERS += \
|
||||
$$PWD/clangreparsesupportivetranslationunitjob.h \
|
||||
$$PWD/clangrequestdocumentannotationsjob.h \
|
||||
$$PWD/clangrequestreferencesjob.h \
|
||||
$$PWD/clangrequesttooltipjob.h \
|
||||
$$PWD/clangresumedocumentjob.h \
|
||||
$$PWD/clangstring.h \
|
||||
$$PWD/clangsupportivetranslationunitinitializer.h \
|
||||
$$PWD/clangsuspenddocumentjob.h \
|
||||
$$PWD/clangtooltipinfocollector.h \
|
||||
$$PWD/clangtranslationunit.h \
|
||||
$$PWD/clangtranslationunits.h \
|
||||
$$PWD/clangtranslationunitupdater.h \
|
||||
@@ -86,8 +88,10 @@ SOURCES += \
|
||||
$$PWD/clangreparsesupportivetranslationunitjob.cpp \
|
||||
$$PWD/clangrequestdocumentannotationsjob.cpp \
|
||||
$$PWD/clangrequestreferencesjob.cpp \
|
||||
$$PWD/clangrequesttooltipjob.cpp \
|
||||
$$PWD/clangsuspenddocumentjob.cpp \
|
||||
$$PWD/clangsupportivetranslationunitinitializer.cpp \
|
||||
$$PWD/clangtooltipinfocollector.cpp \
|
||||
$$PWD/clangtranslationunit.cpp \
|
||||
$$PWD/clangtranslationunits.cpp \
|
||||
$$PWD/clangtranslationunitupdater.cpp \
|
||||
|
||||
@@ -258,6 +258,7 @@ static void fillJobRequest(JobRequest &jobRequest, const MessageType &message)
|
||||
jobRequest.line = message.line();
|
||||
jobRequest.column = message.column();
|
||||
jobRequest.ticketNumber = message.ticketNumber();
|
||||
jobRequest.textCodecName = message.fileContainer().textCodecName();
|
||||
// The unsaved files might get updater later, so take the current
|
||||
// revision for the request.
|
||||
jobRequest.documentRevision = message.fileContainer().documentRevision();
|
||||
@@ -303,6 +304,25 @@ void ClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMessage
|
||||
}
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::requestToolTip(const RequestToolTipMessage &message)
|
||||
{
|
||||
TIME_SCOPE_DURATION("ClangCodeModelServer::requestToolTip");
|
||||
|
||||
try {
|
||||
const Document document = documents.document(message.fileContainer().filePath(),
|
||||
message.fileContainer().projectPartId());
|
||||
DocumentProcessor processor = documentProcessors().processor(document);
|
||||
|
||||
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestToolTip);
|
||||
fillJobRequest(jobRequest, message);
|
||||
|
||||
processor.addJob(jobRequest);
|
||||
processor.process();
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in ClangCodeModelServer::requestToolTip:" << exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
|
||||
{
|
||||
qCDebug(serverLog) << "########## updateVisibleTranslationUnits";
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const RequestReferencesMessage &message) override;
|
||||
void requestFollowSymbol(const RequestFollowSymbolMessage &message) override;
|
||||
void requestToolTip(const RequestToolTipMessage &message) override;
|
||||
|
||||
public: // for tests
|
||||
const Documents &documentsForTestOnly() const;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "clangreparsesupportivetranslationunitjob.h"
|
||||
#include "clangrequestdocumentannotationsjob.h"
|
||||
#include "clangrequestreferencesjob.h"
|
||||
#include "clangrequesttooltipjob.h"
|
||||
#include "clangresumedocumentjob.h"
|
||||
#include "clangsuspenddocumentjob.h"
|
||||
#include "clangupdatedocumentannotationsjob.h"
|
||||
@@ -40,6 +41,7 @@
|
||||
#include <clangsupport/cmbcodecompletedmessage.h>
|
||||
#include <clangsupport/followsymbolmessage.h>
|
||||
#include <clangsupport/referencesmessage.h>
|
||||
#include <clangsupport/tooltipmessage.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -62,6 +64,7 @@ static const char *JobRequestTypeToText(JobRequest::Type type)
|
||||
RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
|
||||
RETURN_TEXT_FOR_CASE(RequestReferences);
|
||||
RETURN_TEXT_FOR_CASE(FollowSymbol);
|
||||
RETURN_TEXT_FOR_CASE(RequestToolTip);
|
||||
RETURN_TEXT_FOR_CASE(SuspendDocument);
|
||||
RETURN_TEXT_FOR_CASE(ResumeDocument);
|
||||
}
|
||||
@@ -126,6 +129,7 @@ static JobRequest::ExpirationConditions expirationConditionsForType(JobRequest::
|
||||
return Conditions(Condition::AnythingChanged);
|
||||
case Type::RequestReferences:
|
||||
case Type::RequestDocumentAnnotations:
|
||||
case Type::RequestToolTip:
|
||||
case Type::FollowSymbol:
|
||||
return Conditions(Condition::DocumentClosed)
|
||||
| Conditions(Condition::DocumentRevisionChanged);
|
||||
@@ -153,8 +157,10 @@ static JobRequest::RunConditions conditionsForType(JobRequest::Type type)
|
||||
Conditions conditions = Conditions(Condition::DocumentUnsuspended)
|
||||
| Conditions(Condition::DocumentVisible);
|
||||
|
||||
if (type == Type::RequestReferences || type == Type::FollowSymbol)
|
||||
if (type == Type::RequestReferences || type == Type::FollowSymbol
|
||||
|| type == Type::RequestToolTip) {
|
||||
conditions |= Condition::CurrentDocumentRevision;
|
||||
}
|
||||
|
||||
if (type != Type::UpdateDocumentAnnotations && type != Type::ParseSupportiveTranslationUnit)
|
||||
conditions |= Condition::DocumentParsed;
|
||||
@@ -192,6 +198,8 @@ IAsyncJob *JobRequest::createJob() const
|
||||
return new RequestDocumentAnnotationsJob();
|
||||
case JobRequest::Type::RequestReferences:
|
||||
return new RequestReferencesJob();
|
||||
case JobRequest::Type::RequestToolTip:
|
||||
return new RequestToolTipJob();
|
||||
case JobRequest::Type::FollowSymbol:
|
||||
return new FollowSymbolJob();
|
||||
case JobRequest::Type::SuspendDocument:
|
||||
@@ -224,6 +232,11 @@ void JobRequest::cancelJob(ClangCodeModelClientInterface &client) const
|
||||
false,
|
||||
ticketNumber));
|
||||
break;
|
||||
case JobRequest::Type::RequestToolTip:
|
||||
client.tooltip(ToolTipMessage(FileContainer(),
|
||||
ToolTipInfo(),
|
||||
ticketNumber));
|
||||
break;
|
||||
case JobRequest::Type::CompleteCode:
|
||||
client.codeCompleted(CodeCompletedMessage(CodeCompletions(),
|
||||
CompletionCorrection::NoCorrection,
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
RequestDocumentAnnotations,
|
||||
RequestReferences,
|
||||
FollowSymbol,
|
||||
RequestToolTip,
|
||||
|
||||
SuspendDocument,
|
||||
ResumeDocument,
|
||||
@@ -118,6 +119,7 @@ public:
|
||||
qint32 funcNameStartLine = -1;
|
||||
qint32 funcNameStartColumn = -1;
|
||||
quint64 ticketNumber = 0;
|
||||
Utf8String textCodecName;
|
||||
bool localReferences = false;
|
||||
};
|
||||
|
||||
|
||||
67
src/tools/clangbackend/source/clangrequesttooltipjob.cpp
Normal file
67
src/tools/clangbackend/source/clangrequesttooltipjob.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "clangrequesttooltipjob.h"
|
||||
|
||||
#include <clangsupport/clangsupportdebugutils.h>
|
||||
#include <clangsupport/clangcodemodelclientinterface.h>
|
||||
#include <clangsupport/tooltipmessage.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
IAsyncJob::AsyncPrepareResult RequestToolTipJob::prepareAsyncRun()
|
||||
{
|
||||
const JobRequest jobRequest = context().jobRequest;
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestToolTip, return AsyncPrepareResult());
|
||||
QTC_ASSERT(acquireDocument(), return AsyncPrepareResult());
|
||||
|
||||
const TranslationUnit translationUnit = *m_translationUnit;
|
||||
const UnsavedFiles unsavedFiles = *context().unsavedFiles;
|
||||
const quint32 line = jobRequest.line;
|
||||
const quint32 column = jobRequest.column;
|
||||
const Utf8String textCodecName = jobRequest.textCodecName;
|
||||
setRunner([translationUnit, unsavedFiles, line, column, textCodecName]() {
|
||||
TIME_SCOPE_DURATION("RequestToolTipJobRunner");
|
||||
|
||||
UnsavedFiles theUnsavedFiles = unsavedFiles;
|
||||
return translationUnit.tooltip(theUnsavedFiles, textCodecName, line, column);
|
||||
});
|
||||
return AsyncPrepareResult{translationUnit.id()};
|
||||
}
|
||||
|
||||
void RequestToolTipJob::finalizeAsyncRun()
|
||||
{
|
||||
if (!context().isOutdated()) {
|
||||
const AsyncResult result = asyncResult();
|
||||
|
||||
context().client->tooltip(ToolTipMessage(m_pinnedFileContainer,
|
||||
result,
|
||||
context().jobRequest.ticketNumber));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
43
src/tools/clangbackend/source/clangrequesttooltipjob.h
Normal file
43
src/tools/clangbackend/source/clangrequesttooltipjob.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <clangsupport/tooltipinfo.h>
|
||||
|
||||
#include "clangdocumentjob.h"
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class RequestToolTipJob : public DocumentJob<ToolTipInfo>
|
||||
{
|
||||
public:
|
||||
using AsyncResult = ToolTipInfo;
|
||||
|
||||
AsyncPrepareResult prepareAsyncRun() override;
|
||||
void finalizeAsyncRun() override;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
531
src/tools/clangbackend/source/clangtooltipinfocollector.cpp
Normal file
531
src/tools/clangbackend/source/clangtooltipinfocollector.cpp
Normal file
@@ -0,0 +1,531 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "clangtooltipinfocollector.h"
|
||||
|
||||
#include "clangbackend_global.h"
|
||||
#include "clangstring.h"
|
||||
#include "cursor.h"
|
||||
#include "sourcerange.h"
|
||||
#include "unsavedfiles.h"
|
||||
#include "unsavedfile.h"
|
||||
|
||||
#include <clangsupport/sourcerangecontainer.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/textfileformat.h>
|
||||
|
||||
#include <utf8string.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QTextCodec>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
namespace {
|
||||
|
||||
Utf8StringVector qualificationPrefixAsVector(const Cursor &cursor)
|
||||
{
|
||||
Utf8StringVector result;
|
||||
|
||||
for (Cursor parent = cursor.semanticParent();
|
||||
parent.isValid() && (parent.kind() == CXCursor_Namespace || parent.isCompoundType());
|
||||
parent = parent.semanticParent()) {
|
||||
result.prepend(parent.spelling());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Utf8String qualificationPrefix(const Cursor &cursor)
|
||||
{
|
||||
// TODO: Implement with qualificationPrefixAsVector()
|
||||
Utf8String qualifiedName;
|
||||
|
||||
for (Cursor parent = cursor.semanticParent();
|
||||
parent.isValid() && (parent.kind() == CXCursor_Namespace);
|
||||
parent = parent.semanticParent()) {
|
||||
qualifiedName = parent.spelling() + Utf8StringLiteral("::") + qualifiedName;
|
||||
}
|
||||
|
||||
return qualifiedName;
|
||||
}
|
||||
|
||||
Utf8String displayName(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.kind() == CXCursor_ClassTemplate) {
|
||||
// TODO: The qualification should be part of the display name. Fix this in libclang.
|
||||
return qualificationPrefix(cursor) + cursor.displayName();
|
||||
}
|
||||
|
||||
return cursor.displayName();
|
||||
}
|
||||
|
||||
Utf8String textForFunctionLike(const Cursor &cursor)
|
||||
{
|
||||
#ifdef IS_PRETTY_DECL_SUPPORTED
|
||||
CXPrintingPolicy policy = clang_getCursorPrintingPolicy(cursor.cx());
|
||||
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_FullyQualifiedName, 1);
|
||||
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_TerseOutput, 1);
|
||||
// Avoid printing attributes/pragmas
|
||||
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_PolishForDeclaration, 1);
|
||||
clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_SuppressInitializers, 1);
|
||||
const Utf8String prettyPrinted = ClangString(
|
||||
clang_getCursorPrettyPrinted(cursor.cx(), policy));
|
||||
clang_PrintingPolicy_dispose(policy);
|
||||
return prettyPrinted;
|
||||
#else
|
||||
// Printing function declarations with displayName() is quite limited:
|
||||
// * result type is not included
|
||||
// * parameter names are not included
|
||||
// * templates in the result type are not included
|
||||
// * no full qualification of the function name
|
||||
return Utf8String(cursor.resultType().spelling())
|
||||
+ Utf8StringLiteral(" ")
|
||||
+ qualificationPrefix(cursor)
|
||||
+ Utf8String(cursor.displayName());
|
||||
#endif
|
||||
}
|
||||
|
||||
Utf8String textForEnumConstantDecl(const Cursor &cursor)
|
||||
{
|
||||
const Cursor semanticParent = cursor.semanticParent();
|
||||
QTC_ASSERT(semanticParent.kind() == CXCursor_EnumDecl, return Utf8String());
|
||||
|
||||
const Type enumType = semanticParent.enumType();
|
||||
if (enumType.isUnsigned())
|
||||
return Utf8String::number(cursor.enumConstantUnsignedValue());
|
||||
return Utf8String::number(cursor.enumConstantValue());
|
||||
}
|
||||
|
||||
Utf8String textForInclusionDirective(const Cursor &cursor)
|
||||
{
|
||||
const CXFile includedFile = cursor.includedFile();
|
||||
const Utf8String fileName = ClangString(clang_getFileName(includedFile));
|
||||
|
||||
return QDir::toNativeSeparators(fileName.toString());
|
||||
}
|
||||
|
||||
Utf8String textForAnyTypeAlias(const Cursor &cursor)
|
||||
{
|
||||
// For a CXCursor_TypeAliasTemplateDecl the type of cursor/referenced
|
||||
// is invalid, so we do not get the underlying type. This here solely
|
||||
// reports the unresolved name instead of the empty string.
|
||||
if (cursor.kind() == CXCursor_TypeAliasTemplateDecl)
|
||||
return cursor.displayName();
|
||||
|
||||
return cursor.type().alias().utf8Spelling();
|
||||
}
|
||||
|
||||
bool includeSizeForCursor(const Cursor &cursor)
|
||||
{
|
||||
return cursor.isCompoundType()
|
||||
|| cursor.kind() == CXCursor_EnumDecl
|
||||
|| cursor.kind() == CXCursor_UnionDecl
|
||||
|| cursor.kind() == CXCursor_FieldDecl;
|
||||
}
|
||||
|
||||
Utf8String sizeInBytes(const Cursor &cursor)
|
||||
{
|
||||
if (includeSizeForCursor(cursor)) {
|
||||
bool ok = false;
|
||||
const long long size = cursor.type().sizeOf(&ok);
|
||||
if (ok)
|
||||
return Utf8String::number(size);
|
||||
}
|
||||
|
||||
return Utf8String();
|
||||
}
|
||||
|
||||
Cursor referencedCursor(const Cursor &cursor)
|
||||
{
|
||||
// Query the referenced cursor directly instead of first testing with cursor.isReference().
|
||||
// cursor.isReference() reports false for e.g. CXCursor_DeclRefExpr or CXCursor_CallExpr
|
||||
// although it returns a valid cursor.
|
||||
const Cursor referenced = cursor.referenced();
|
||||
if (referenced.isValid())
|
||||
return referenced;
|
||||
|
||||
const Cursor definition = cursor.definition();
|
||||
if (definition.isValid())
|
||||
return definition;
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
class ToolTipInfoCollector
|
||||
{
|
||||
public:
|
||||
ToolTipInfoCollector(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
const Utf8String &mainFilePath,
|
||||
CXTranslationUnit cxTranslationUnit);
|
||||
|
||||
ToolTipInfo collect(uint line, uint column) const;
|
||||
|
||||
private:
|
||||
Utf8String text(const Cursor &cursor, const Cursor &referenced) const;
|
||||
Utf8String textForMacroExpansion(const Cursor &cursor) const;
|
||||
Utf8String textForNamespaceAlias(const Cursor &cursor) const;
|
||||
|
||||
ToolTipInfo qDocInfo(const Cursor &cursor) const;
|
||||
|
||||
CXSourceLocation toCXSourceLocation(uint line, uint column) const;
|
||||
|
||||
UnsavedFile unsavedFile(const Utf8String &filePath) const;
|
||||
Utf8String lineRange(const Utf8String &filePath, unsigned fromLine, unsigned toLine) const;
|
||||
|
||||
private:
|
||||
UnsavedFiles &m_unsavedFiles;
|
||||
const Utf8String m_textCodecName;
|
||||
|
||||
const Utf8String m_mainFilePath;
|
||||
CXTranslationUnit m_cxTranslationUnit = nullptr;
|
||||
|
||||
};
|
||||
|
||||
ToolTipInfoCollector::ToolTipInfoCollector(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
const Utf8String &mainFilePath,
|
||||
CXTranslationUnit cxTranslationUnit)
|
||||
: m_unsavedFiles(unsavedFiles)
|
||||
, m_textCodecName(textCodecName)
|
||||
, m_mainFilePath(mainFilePath)
|
||||
, m_cxTranslationUnit(cxTranslationUnit)
|
||||
{
|
||||
}
|
||||
|
||||
Utf8String ToolTipInfoCollector::text(const Cursor &cursor, const Cursor &referenced) const
|
||||
{
|
||||
if (cursor.kind() == CXCursor_MacroExpansion)
|
||||
return textForMacroExpansion(referenced);
|
||||
|
||||
if (referenced.kind() == CXCursor_EnumConstantDecl)
|
||||
return textForEnumConstantDecl(referenced);
|
||||
|
||||
if (referenced.kind() == CXCursor_InclusionDirective)
|
||||
return textForInclusionDirective(referenced);
|
||||
|
||||
if (referenced.kind() == CXCursor_Namespace)
|
||||
return qualificationPrefix(referenced) + referenced.spelling();
|
||||
|
||||
if (referenced.kind() == CXCursor_NamespaceAlias)
|
||||
return textForNamespaceAlias(referenced);
|
||||
|
||||
if (referenced.isAnyTypeAlias())
|
||||
return textForAnyTypeAlias(referenced);
|
||||
|
||||
if (referenced.isFunctionLike())
|
||||
return textForFunctionLike(referenced);
|
||||
|
||||
if (referenced.type().canonical().isBuiltinType())
|
||||
return referenced.type().canonical().builtinTypeToString();
|
||||
|
||||
if (referenced.kind() == CXCursor_VarDecl)
|
||||
return referenced.type().spelling(); // e.g. "Zii<int>"
|
||||
|
||||
const Type referencedType = referenced.type();
|
||||
if (referencedType.isValid()) {
|
||||
// Generally, the type includes the qualification but has this limitations:
|
||||
// * namespace aliases are not resolved
|
||||
// * outer class of a inner template class is not included
|
||||
// The type includes the qualification, but not resolved namespace aliases.
|
||||
|
||||
// For a CXType_Record, this also includes e.g. "const " as prefix.
|
||||
return referencedType.canonical().utf8Spelling();
|
||||
}
|
||||
|
||||
return displayName(referenced);
|
||||
}
|
||||
|
||||
Utf8String ToolTipInfoCollector::textForMacroExpansion(const Cursor &cursor) const
|
||||
{
|
||||
QTC_ASSERT(cursor.kind() == CXCursor_MacroDefinition, return Utf8String());
|
||||
|
||||
const SourceRange sourceRange = cursor.sourceRange();
|
||||
const SourceLocation start = sourceRange.start();
|
||||
const SourceLocation end = sourceRange.end();
|
||||
|
||||
return lineRange(start.filePath(), start.line(), end.line());
|
||||
}
|
||||
|
||||
Utf8String ToolTipInfoCollector::textForNamespaceAlias(const Cursor &cursor) const
|
||||
{
|
||||
// TODO: Add some libclang API to get the aliased name straight away.
|
||||
|
||||
CXToken *cxTokens = nullptr;
|
||||
uint cxTokenCount = 0;
|
||||
|
||||
clang_tokenize(m_cxTranslationUnit, cursor.cxSourceRange(), &cxTokens, &cxTokenCount);
|
||||
|
||||
Utf8String aliasedName;
|
||||
// Start at 3 in order to skip these tokens: namespace X =
|
||||
for (uint i = 3; i < cxTokenCount; ++i)
|
||||
aliasedName += ClangString(clang_getTokenSpelling(m_cxTranslationUnit, cxTokens[i]));
|
||||
|
||||
clang_disposeTokens(m_cxTranslationUnit, cxTokens, cxTokenCount);
|
||||
|
||||
return aliasedName;
|
||||
}
|
||||
|
||||
static Utf8String typeName(const Type &type)
|
||||
{
|
||||
return type.declaration().spelling();
|
||||
}
|
||||
|
||||
static Utf8String qdocMark(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.kind() == CXCursor_ClassTemplate)
|
||||
return cursor.spelling();
|
||||
|
||||
if (cursor.type().kind() == CXType_Enum
|
||||
|| cursor.type().kind() == CXType_Typedef
|
||||
|| cursor.type().kind() == CXType_Record)
|
||||
return typeName(cursor.type());
|
||||
|
||||
Utf8String text = cursor.displayName();
|
||||
if (cursor.kind() == CXCursor_FunctionDecl) {
|
||||
// TODO: Remove this workaround by fixing this in
|
||||
// libclang with the help of CXPrintingPolicy.
|
||||
text.replace(Utf8StringLiteral("<>"), Utf8String());
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static ToolTipInfo::QdocCategory qdocCategory(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.isFunctionLike())
|
||||
return ToolTipInfo::Function;
|
||||
|
||||
if (cursor.kind() == CXCursor_MacroDefinition)
|
||||
return ToolTipInfo::Macro;
|
||||
|
||||
if (cursor.kind() == CXCursor_EnumConstantDecl)
|
||||
return ToolTipInfo::Enum;
|
||||
|
||||
if (cursor.type().kind() == CXType_Enum)
|
||||
return ToolTipInfo::Enum;
|
||||
|
||||
if (cursor.kind() == CXCursor_InclusionDirective)
|
||||
return ToolTipInfo::Brief;
|
||||
|
||||
// TODO: Handle CXCursor_NamespaceAlias, too?!
|
||||
if (cursor.kind() == CXCursor_Namespace)
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
if (cursor.isCompoundType())
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
if (cursor.kind() == CXCursor_NamespaceAlias)
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
if (cursor.type().kind() == CXType_Typedef)
|
||||
return ToolTipInfo::Typedef;
|
||||
|
||||
if (cursor.type().kind() == CXType_Record)
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
if (cursor.kind() == CXCursor_TypeAliasTemplateDecl)
|
||||
return ToolTipInfo::Typedef;
|
||||
|
||||
if (cursor.kind() == CXCursor_ClassTemplate)
|
||||
return ToolTipInfo::ClassOrNamespace;
|
||||
|
||||
return ToolTipInfo::Unknown;
|
||||
}
|
||||
|
||||
static Utf8String name(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.type().kind() == CXType_Record || cursor.kind() == CXCursor_EnumDecl)
|
||||
return typeName(cursor.type());
|
||||
|
||||
return cursor.spelling();
|
||||
}
|
||||
|
||||
static Utf8StringVector qDocIdCandidates(const Cursor &cursor)
|
||||
{
|
||||
Utf8StringVector components = qualificationPrefixAsVector(cursor);
|
||||
if (components.isEmpty())
|
||||
return { name(cursor) };
|
||||
|
||||
components << name(cursor);
|
||||
Utf8StringVector result;
|
||||
Utf8String name;
|
||||
for (auto it = components.rbegin(); it != components.rend(); ++it) {
|
||||
if (name.isEmpty())
|
||||
name = *it;
|
||||
else
|
||||
name = *it + (Utf8StringLiteral("::") + name);
|
||||
|
||||
result.prepend(name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Add libclang API for this?!
|
||||
static bool isBuiltinOrPointerToBuiltin(const Type &type)
|
||||
{
|
||||
Type theType = type;
|
||||
|
||||
if (theType.isBuiltinType())
|
||||
return true;
|
||||
|
||||
// TODO: Simplify
|
||||
// TODO: Test with **
|
||||
while (theType.pointeeType().isValid()) {
|
||||
theType = theType.pointeeType();
|
||||
if (theType.isBuiltinType())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ToolTipInfo ToolTipInfoCollector::qDocInfo(const Cursor &cursor) const
|
||||
{
|
||||
ToolTipInfo result;
|
||||
|
||||
if (isBuiltinOrPointerToBuiltin(cursor.type()))
|
||||
return result;
|
||||
|
||||
result.setQdocIdCandidates(qDocIdCandidates(cursor));
|
||||
result.setQdocMark(qdocMark(cursor));
|
||||
result.setQdocCategory(qdocCategory(cursor));
|
||||
|
||||
if (cursor.type().kind() == CXType_Record) {
|
||||
result.setQdocIdCandidates(qDocIdCandidates(cursor.type().declaration()));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cursor.kind() == CXCursor_VarDecl || cursor.kind() == CXCursor_FieldDecl) {
|
||||
result.setQdocMark(typeName(cursor.type()));
|
||||
// maybe template instantiation
|
||||
if (cursor.type().kind() == CXType_Unexposed && cursor.type().canonical().kind() == CXType_Record) {
|
||||
result.setQdocIdCandidates(qDocIdCandidates(cursor.type().canonical().declaration()));
|
||||
result.setQdocCategory(ToolTipInfo::ClassOrNamespace);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle also RValueReference()
|
||||
if (cursor.type().isLValueReference()) {
|
||||
const Cursor pointeeTypeDeclaration = cursor.type().pointeeType().declaration();
|
||||
result.setQdocIdCandidates(qDocIdCandidates(pointeeTypeDeclaration));
|
||||
result.setQdocMark(pointeeTypeDeclaration.spelling());
|
||||
result.setQdocCategory(qdocCategory(pointeeTypeDeclaration));
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CXSourceLocation ToolTipInfoCollector::toCXSourceLocation(uint line, uint column) const
|
||||
{
|
||||
return clang_getLocation(m_cxTranslationUnit,
|
||||
clang_getFile(m_cxTranslationUnit,
|
||||
m_mainFilePath.constData()),
|
||||
line,
|
||||
column);
|
||||
}
|
||||
|
||||
UnsavedFile ToolTipInfoCollector::unsavedFile(const Utf8String &filePath) const
|
||||
{
|
||||
const UnsavedFile &unsavedFile = m_unsavedFiles.unsavedFile(filePath);
|
||||
if (!unsavedFile.filePath().isEmpty())
|
||||
return unsavedFile;
|
||||
|
||||
// Create an unsaved file with the file content from disk.
|
||||
// TODO: Make use of clang_getFileContents() instead of reading from disk.
|
||||
QTextCodec *codec = QTextCodec::codecForName(m_textCodecName);
|
||||
QByteArray fileContent;
|
||||
QString errorString;
|
||||
using namespace Utils;
|
||||
const TextFileFormat::ReadResult readResult
|
||||
= TextFileFormat::readFileUTF8(filePath.toString(), codec, &fileContent, &errorString);
|
||||
if (readResult != TextFileFormat::ReadSuccess) {
|
||||
qWarning() << "Failed to read file" << filePath << ":" << errorString;
|
||||
return UnsavedFile();
|
||||
}
|
||||
|
||||
return UnsavedFile(filePath, Utf8String::fromByteArray(fileContent));
|
||||
}
|
||||
|
||||
Utf8String ToolTipInfoCollector::lineRange(const Utf8String &filePath,
|
||||
unsigned fromLine,
|
||||
unsigned toLine) const
|
||||
{
|
||||
if (toLine < fromLine)
|
||||
return Utf8String();
|
||||
|
||||
const UnsavedFile file = unsavedFile(filePath);
|
||||
if (file.fileContent().isEmpty())
|
||||
return Utf8String();
|
||||
|
||||
return file.lineRange(fromLine, toLine);
|
||||
}
|
||||
|
||||
ToolTipInfo ToolTipInfoCollector::collect(uint line, uint column) const
|
||||
{
|
||||
const Cursor cursor = clang_getCursor(m_cxTranslationUnit, toCXSourceLocation(line, column));
|
||||
if (!cursor.isValid())
|
||||
return ToolTipInfo(); // E.g. cursor on ifdeffed out range
|
||||
|
||||
const Cursor referenced = referencedCursor(cursor);
|
||||
QTC_CHECK(referenced.isValid());
|
||||
|
||||
ToolTipInfo info;
|
||||
info.setText(text(cursor, referenced));
|
||||
info.setBriefComment(referenced.briefComment());
|
||||
|
||||
{
|
||||
ToolTipInfo qDocToolTipInfo = qDocInfo(referenced);
|
||||
info.setQdocIdCandidates(qDocToolTipInfo.qdocIdCandidates());
|
||||
info.setQdocMark(qDocToolTipInfo.qdocMark());
|
||||
info.setQdocCategory(qDocToolTipInfo.qdocCategory());
|
||||
}
|
||||
|
||||
info.setSizeInBytes(sizeInBytes(cursor));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ToolTipInfo collectToolTipInfo(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
const Utf8String &mainFilePath,
|
||||
CXTranslationUnit cxTranslationUnit,
|
||||
uint line,
|
||||
uint column)
|
||||
{
|
||||
ToolTipInfoCollector collector(unsavedFiles, textCodecName, mainFilePath, cxTranslationUnit);
|
||||
const ToolTipInfo info = collector.collect(line, column);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
45
src/tools/clangbackend/source/clangtooltipinfocollector.h
Normal file
45
src/tools/clangbackend/source/clangtooltipinfocollector.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <utf8string.h>
|
||||
|
||||
#include <clangsupport/tooltipinfo.h>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class UnsavedFiles;
|
||||
|
||||
ToolTipInfo collectToolTipInfo(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
const Utf8String &mainFilePath,
|
||||
CXTranslationUnit cxTranslationUnit,
|
||||
uint line,
|
||||
uint column);
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "clangbackend_global.h"
|
||||
#include "clangreferencescollector.h"
|
||||
#include "clangtooltipinfocollector.h"
|
||||
#include "clangtranslationunitupdater.h"
|
||||
#include "clangfollowsymbol.h"
|
||||
#include "clangfollowsymboljob.h"
|
||||
@@ -139,6 +140,20 @@ void TranslationUnit::extractDocumentAnnotations(
|
||||
skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers();
|
||||
}
|
||||
|
||||
|
||||
ToolTipInfo TranslationUnit::tooltip(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
uint line,
|
||||
uint column) const
|
||||
{
|
||||
return collectToolTipInfo(unsavedFiles,
|
||||
textCodecName,
|
||||
filePath(),
|
||||
m_cxTranslationUnit,
|
||||
line,
|
||||
column);
|
||||
}
|
||||
|
||||
ReferencesResult TranslationUnit::references(uint line, uint column, bool localReferences) const
|
||||
{
|
||||
return collectReferences(m_cxTranslationUnit, line, column, localReferences);
|
||||
|
||||
@@ -41,6 +41,7 @@ class SkippedSourceRanges;
|
||||
class SourceLocation;
|
||||
class SourceRange;
|
||||
class SourceRangeContainer;
|
||||
class ToolTipInfo;
|
||||
class TranslationUnitUpdateInput;
|
||||
class TranslationUnitUpdateResult;
|
||||
class UnsavedFiles;
|
||||
@@ -86,6 +87,10 @@ public:
|
||||
|
||||
|
||||
ReferencesResult references(uint line, uint column, bool localReferences = false) const;
|
||||
ToolTipInfo tooltip(UnsavedFiles &unsavedFiles,
|
||||
const Utf8String &textCodecName,
|
||||
uint line,
|
||||
uint column) const;
|
||||
DiagnosticSet diagnostics() const;
|
||||
|
||||
SourceLocation sourceLocationAt(uint line, uint column) const;
|
||||
|
||||
@@ -84,6 +84,16 @@ bool Type::isBuiltinType() const
|
||||
return cxType.kind >= CXType_FirstBuiltin && cxType.kind <= CXType_LastBuiltin;
|
||||
}
|
||||
|
||||
bool Type::isUnsigned() const
|
||||
{
|
||||
return cxType.kind == CXType_UChar
|
||||
|| cxType.kind == CXType_UShort
|
||||
|| cxType.kind == CXType_UInt
|
||||
|| cxType.kind == CXType_ULong
|
||||
|| cxType.kind == CXType_ULongLong
|
||||
|| cxType.kind == CXType_UInt128;
|
||||
}
|
||||
|
||||
Utf8String Type::utf8Spelling() const
|
||||
{
|
||||
return ClangString(clang_getTypeSpelling(cxType));
|
||||
@@ -94,6 +104,83 @@ ClangString Type::spelling() const
|
||||
return ClangString(clang_getTypeSpelling(cxType));
|
||||
}
|
||||
|
||||
static const char *builtinTypeToText(CXTypeKind kind)
|
||||
{
|
||||
// CLANG-UPGRADE-CHECK: Check for added built-in types.
|
||||
|
||||
switch (kind) {
|
||||
case CXType_Void:
|
||||
return "void";
|
||||
case CXType_Bool:
|
||||
return "bool";
|
||||
|
||||
// See also ${CLANG_REPOSITORY}/lib/Sema/SemaChecking.cpp - IsSameCharType().
|
||||
case CXType_Char_U:
|
||||
case CXType_UChar:
|
||||
return "unsigned char";
|
||||
case CXType_Char_S:
|
||||
case CXType_SChar:
|
||||
return "signed char";
|
||||
|
||||
case CXType_Char16:
|
||||
return "char16_t";
|
||||
case CXType_Char32:
|
||||
return "char32_t";
|
||||
case CXType_WChar:
|
||||
return "wchar_t";
|
||||
|
||||
case CXType_UShort:
|
||||
return "unsigned short";
|
||||
case CXType_UInt:
|
||||
return "unsigned int";
|
||||
case CXType_ULong:
|
||||
return "unsigned long";
|
||||
case CXType_ULongLong:
|
||||
return "unsigned long long";
|
||||
case CXType_Short:
|
||||
return "short";
|
||||
|
||||
case CXType_Int:
|
||||
return "int";
|
||||
case CXType_Long:
|
||||
return "long";
|
||||
case CXType_LongLong:
|
||||
return "long long";
|
||||
|
||||
case CXType_Float:
|
||||
return "float";
|
||||
case CXType_Double:
|
||||
return "double";
|
||||
case CXType_LongDouble:
|
||||
return "long double";
|
||||
|
||||
case CXType_NullPtr:
|
||||
return "nullptr_t";
|
||||
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html
|
||||
case CXType_Int128: return "__int128";
|
||||
case CXType_UInt128: return "unsigned __int128";
|
||||
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html
|
||||
case CXType_Float128: return "__float128";
|
||||
// CLANG-UPGRADE-CHECK: CXType_Float16 available with >= clang-6.0:
|
||||
// case CXType_Float16: return "_Float16";
|
||||
|
||||
// https://www.khronos.org/registry/OpenCL/sdk/2.1/docs/man/xhtml/scalarDataTypes.html
|
||||
case CXType_Half:
|
||||
return "half";
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Utf8String Type::builtinTypeToString() const
|
||||
{
|
||||
const char *text = builtinTypeToText(cxType.kind);
|
||||
return Utf8String::fromByteArray(QByteArray::fromRawData(text, strlen(text)));
|
||||
}
|
||||
|
||||
int Type::argumentCount() const
|
||||
{
|
||||
return clang_getNumArgTypes(cxType);
|
||||
@@ -129,6 +216,16 @@ Cursor Type::declaration() const
|
||||
return clang_getTypeDeclaration(cxType);
|
||||
}
|
||||
|
||||
long long Type::sizeOf(bool *isValid) const
|
||||
{
|
||||
const long long size = clang_Type_getSizeOf(cxType);
|
||||
*isValid = size != CXTypeLayoutError_Invalid
|
||||
&& size != CXTypeLayoutError_Incomplete
|
||||
&& size != CXTypeLayoutError_Dependent;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
CXTypeKind Type::kind() const
|
||||
{
|
||||
return cxType.kind;
|
||||
|
||||
@@ -53,9 +53,11 @@ public:
|
||||
bool isReferencingConstant() const;
|
||||
bool isOutputArgument() const;
|
||||
bool isBuiltinType() const;
|
||||
bool isUnsigned() const;
|
||||
|
||||
Utf8String utf8Spelling() const;
|
||||
ClangString spelling() const;
|
||||
Utf8String builtinTypeToString() const;
|
||||
int argumentCount() const;
|
||||
|
||||
Type alias() const;
|
||||
@@ -66,6 +68,8 @@ public:
|
||||
|
||||
Cursor declaration() const;
|
||||
|
||||
long long sizeOf(bool *isValid) const;
|
||||
|
||||
CXTypeKind kind() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -158,6 +158,14 @@ bool Cursor::isTemplateLike() const
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
bool Cursor::isAnyTypeAlias() const
|
||||
{
|
||||
const CXCursorKind k = kind();
|
||||
return k == CXCursor_TypeAliasDecl
|
||||
|| k == CXCursor_TypedefDecl
|
||||
|| k == CXCursor_TypeAliasTemplateDecl;
|
||||
}
|
||||
|
||||
bool Cursor::hasFinalFunctionAttribute() const
|
||||
{
|
||||
bool hasFinal = false;
|
||||
@@ -248,11 +256,31 @@ Type Cursor::nonPointerTupe() const
|
||||
return typeResult;
|
||||
}
|
||||
|
||||
Type Cursor::enumType() const
|
||||
{
|
||||
return clang_getEnumDeclIntegerType(cxCursor);
|
||||
}
|
||||
|
||||
long long Cursor::enumConstantValue() const
|
||||
{
|
||||
return clang_getEnumConstantDeclValue(cxCursor);
|
||||
}
|
||||
|
||||
unsigned long long Cursor::enumConstantUnsignedValue() const
|
||||
{
|
||||
return clang_getEnumConstantDeclUnsignedValue(cxCursor);
|
||||
}
|
||||
|
||||
Cursor Cursor::specializedCursorTemplate() const
|
||||
{
|
||||
return clang_getSpecializedCursorTemplate(cxCursor);
|
||||
}
|
||||
|
||||
CXFile Cursor::includedFile() const
|
||||
{
|
||||
return clang_getIncludedFile(cxCursor);
|
||||
}
|
||||
|
||||
SourceLocation Cursor::sourceLocation() const
|
||||
{
|
||||
return clang_getCursorLocation(cxCursor);
|
||||
@@ -341,6 +369,11 @@ Cursor Cursor::functionBase() const
|
||||
return functionBaseCursor;
|
||||
}
|
||||
|
||||
Type Cursor::resultType() const
|
||||
{
|
||||
return clang_getResultType(type().cxType);
|
||||
}
|
||||
|
||||
Cursor Cursor::argument(int index) const
|
||||
{
|
||||
return clang_Cursor_getArgument(cxCursor, index);
|
||||
@@ -398,6 +431,11 @@ CXCursorKind Cursor::kind() const
|
||||
return clang_getCursorKind(cxCursor);
|
||||
}
|
||||
|
||||
CXCursor Cursor::cx() const
|
||||
{
|
||||
return cxCursor;
|
||||
}
|
||||
|
||||
bool operator==(const Cursor &first, const Cursor &second)
|
||||
{
|
||||
return clang_equalCursors(first.cxCursor, second.cxCursor);
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
bool isFunctionLike() const;
|
||||
bool isConstructorOrDestructor() const;
|
||||
bool isTemplateLike() const;
|
||||
bool isAnyTypeAlias() const;
|
||||
bool hasFinalFunctionAttribute() const;
|
||||
bool hasFinalClassAttribute() const;
|
||||
bool isUnexposed() const;
|
||||
@@ -81,6 +82,10 @@ public:
|
||||
|
||||
Type type() const;
|
||||
Type nonPointerTupe() const;
|
||||
Type enumType() const;
|
||||
|
||||
long long enumConstantValue() const;
|
||||
unsigned long long enumConstantUnsignedValue() const;
|
||||
|
||||
SourceLocation sourceLocation() const;
|
||||
CXSourceLocation cxSourceLocation() const;
|
||||
@@ -92,17 +97,19 @@ public:
|
||||
|
||||
Cursor definition() const;
|
||||
Cursor canonical() const;
|
||||
Cursor alias() const;
|
||||
Cursor referenced() const;
|
||||
Cursor semanticParent() const;
|
||||
Cursor lexicalParent() const;
|
||||
Cursor functionBaseDeclaration() const;
|
||||
Cursor functionBase() const;
|
||||
Type resultType() const;
|
||||
Cursor argument(int index) const;
|
||||
unsigned overloadedDeclarationsCount() const;
|
||||
Cursor overloadedDeclaration(unsigned index) const;
|
||||
Cursor specializedCursorTemplate() const;
|
||||
|
||||
CXFile includedFile() const;
|
||||
|
||||
void collectOutputArgumentRangesTo(
|
||||
std::vector<CXSourceRange> &outputArgumentRanges) const;
|
||||
std::vector<CXSourceRange> outputArgumentRanges() const;
|
||||
@@ -112,6 +119,8 @@ public:
|
||||
template <class VisitorCallback>
|
||||
void visit(VisitorCallback visitorCallback) const;
|
||||
|
||||
CXCursor cx() const;
|
||||
|
||||
private:
|
||||
CXCursor cxCursor;
|
||||
};
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
UnsavedFile::UnsavedFile()
|
||||
@@ -79,6 +81,25 @@ bool UnsavedFile::hasCharacterAt(uint line, uint column, char character) const
|
||||
return positionIsOk && hasCharacterAt(utf8Position, character);
|
||||
}
|
||||
|
||||
Utf8String UnsavedFile::lineRange(uint fromLine, uint toLine) const
|
||||
{
|
||||
QTC_ASSERT(fromLine <= toLine, return Utf8String());
|
||||
|
||||
// Find start of first line
|
||||
bool ok = false;
|
||||
const uint fromPosition = toUtf8Position(fromLine, 1, &ok);
|
||||
QTC_ASSERT(ok, return Utf8String());
|
||||
|
||||
// Find end of last line
|
||||
uint toPosition = toUtf8Position(toLine, 1, &ok);
|
||||
QTC_ASSERT(ok, return Utf8String());
|
||||
const uint endPosition = uint(m_fileContent.byteSize());
|
||||
while (toPosition < endPosition && m_fileContent.constData()[toPosition] != '\n')
|
||||
++toPosition;
|
||||
|
||||
return m_fileContent.mid(int(fromPosition), int(toPosition - fromPosition));
|
||||
}
|
||||
|
||||
bool UnsavedFile::hasCharacterAt(uint position, char character) const
|
||||
{
|
||||
if (position < uint(m_fileContent.byteSize()))
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
// 1-based line and column
|
||||
uint toUtf8Position(uint line, uint column, bool *ok) const;
|
||||
bool hasCharacterAt(uint line, uint column, char character) const;
|
||||
Utf8String lineRange(uint fromLine, uint toLine) const;
|
||||
|
||||
// 0-based position
|
||||
bool hasCharacterAt(uint position, char character) const;
|
||||
|
||||
Reference in New Issue
Block a user