&results, quint64 contexts, bool isSignalSlotCompletion)
+ : m_results(results)
+ , m_contexts(contexts)
+ , m_isSignalSlotCompletion(isSignalSlotCompletion)
+{
+}
+
+void CompletionProposalsBuilder::operator ()(const CXCompletionResult &cxResult)
+{
+ resetWithResult(cxResult);
+
+#if defined(CINDEX_VERSION) && (CINDEX_VERSION > 5)
+ const QString brief = Internal::getQString(clang_getCompletionBriefComment(cxResult.CompletionString));
+ if (!brief.isEmpty())
+ m_comment += QLatin1String("Brief: ") + Qt::escape(brief);
+#endif
+
+ if (m_resultAvailability == CodeCompletionResult::Deprecated) {
+ m_comment += QLatin1String("@note ");
+ m_comment += QCoreApplication::translate("deprecated C++ symbol", "Is deprecated");
+ }
+
+ m_hint = QLatin1String("");
+ switch (m_resultKind) {
+ case CodeCompletionResult::ObjCMessageCompletionKind:
+ concatChunksForObjectiveCMessage(cxResult);
+ break;
+ case CodeCompletionResult::ClassCompletionKind:
+ case CodeCompletionResult::NamespaceCompletionKind:
+ case CodeCompletionResult::EnumeratorCompletionKind:
+ concatChunksForNestedName(cxResult.CompletionString);
+ break;
+ case CodeCompletionResult::ClangSnippetKind:
+ concatChunksAsSnippet(cxResult.CompletionString);
+ break;
+ case CodeCompletionResult::SlotCompletionKind:
+ case CodeCompletionResult::SignalCompletionKind:
+ if (m_isSignalSlotCompletion)
+ concatSlotSignalSignature(cxResult.CompletionString);
+ else
+ concatChunksOnlyTypedText(cxResult.CompletionString);
+ break;
+ default:
+ concatChunksOnlyTypedText(cxResult.CompletionString);
+ break;
+ }
+ m_hint += QLatin1String("
");
+ m_hint += m_comment;
+
+ finalize();
+ foreach (const OptionalChunk &chunk, m_optionalChunks) {
+ m_hint.insert(chunk.positionInHint, chunk.hint);
+ finalize();
+ }
+}
+
+/**
+ * @return Internal ClangCodeModel's completion kind, that affects further postprocessing
+ */
+CodeCompletionResult::Kind CompletionProposalsBuilder::getKind(const CXCompletionResult &cxResult)
+{
+ CXCompletionString complStr = cxResult.CompletionString;
+ CXCursorKind cursorKind = cxResult.CursorKind;
+
+ switch (cursorKind) {
+ case CXCursor_Constructor:
+ return CodeCompletionResult::ConstructorCompletionKind;
+
+ case CXCursor_Destructor:
+ return CodeCompletionResult::DestructorCompletionKind;
+
+ case CXCursor_CXXMethod: {
+ const unsigned numAnnotations = clang_getCompletionNumAnnotations(complStr);
+ bool isSignal = false, isSlot = false;
+ for (unsigned i = 0; i < numAnnotations && !isSignal && !isSlot; ++i) {
+ CXString cxAnn = clang_getCompletionAnnotation(complStr, i);
+ QString ann = Internal::getQString(cxAnn);
+ isSignal = ann == QLatin1String("qt_signal");
+ isSlot = ann == QLatin1String("qt_slot");
+ }
+ if (isSignal)
+ return CodeCompletionResult::SignalCompletionKind;
+ if (isSlot)
+ return CodeCompletionResult::SlotCompletionKind;
+ } // intentional fall-through!
+ case CXCursor_ConversionFunction:
+ case CXCursor_FunctionDecl:
+ case CXCursor_FunctionTemplate:
+ case CXCursor_MemberRef:
+ case CXCursor_MemberRefExpr:
+ return CodeCompletionResult::FunctionCompletionKind;
+ break;
+
+ case CXCursor_FieldDecl:
+ case CXCursor_VarDecl:
+ case CXCursor_ParmDecl:
+ case CXCursor_ObjCIvarDecl:
+ case CXCursor_ObjCPropertyDecl:
+ case CXCursor_ObjCSynthesizeDecl:
+ case CXCursor_NonTypeTemplateParameter:
+ return CodeCompletionResult::VariableCompletionKind;
+
+ case CXCursor_Namespace:
+ case CXCursor_NamespaceAlias:
+ case CXCursor_NamespaceRef:
+ return CodeCompletionResult::NamespaceCompletionKind;
+
+ case CXCursor_StructDecl:
+ case CXCursor_UnionDecl:
+ case CXCursor_ClassDecl:
+ case CXCursor_TypeRef:
+ case CXCursor_TemplateRef:
+ case CXCursor_TypedefDecl:
+ case CXCursor_ClassTemplate:
+ case CXCursor_ClassTemplatePartialSpecialization:
+ case CXCursor_ObjCClassRef:
+ case CXCursor_ObjCInterfaceDecl:
+ case CXCursor_ObjCImplementationDecl:
+ case CXCursor_ObjCCategoryDecl:
+ case CXCursor_ObjCCategoryImplDecl:
+ case CXCursor_ObjCProtocolDecl:
+ case CXCursor_ObjCProtocolRef:
+ case CXCursor_TemplateTypeParameter:
+ case CXCursor_TemplateTemplateParameter:
+ return CodeCompletionResult::ClassCompletionKind;
+
+ case CXCursor_EnumConstantDecl:
+ return CodeCompletionResult::EnumeratorCompletionKind;
+
+ case CXCursor_EnumDecl:
+ return CodeCompletionResult::EnumCompletionKind;
+
+ case CXCursor_MacroDefinition: {
+ const unsigned numChunks = clang_getNumCompletionChunks(complStr);
+ for (unsigned i = 0; i < numChunks; ++i) {
+ CXCompletionChunkKind kind = clang_getCompletionChunkKind(complStr, i);
+ if (kind == CXCompletionChunk_Placeholder) {
+ return CodeCompletionResult::FunctionCompletionKind;
+ }
+ }
+ return CodeCompletionResult::PreProcessorCompletionKind;
+ }
+
+ case CXCursor_PreprocessingDirective:
+ case CXCursor_MacroExpansion:
+ case CXCursor_InclusionDirective:
+ return CodeCompletionResult::PreProcessorCompletionKind;
+
+ case CXCursor_ObjCClassMethodDecl:
+ case CXCursor_ObjCInstanceMethodDecl:
+ return CodeCompletionResult::ObjCMessageCompletionKind;
+
+ case CXCursor_NotImplemented: {
+ const unsigned numChunks = clang_getNumCompletionChunks(complStr);
+ for (unsigned i = 0; i < numChunks; ++i) {
+ CXCompletionChunkKind kind = clang_getCompletionChunkKind(complStr, i);
+ if (kind == CXCompletionChunk_Placeholder) {
+ return CodeCompletionResult::ClangSnippetKind;
+ }
+ }
+ return CodeCompletionResult::KeywordCompletionKind;
+ }
+
+ default:
+ break;
+ }
+
+ return CodeCompletionResult::Other;
+}
+
+/**
+ * @return Symbol availability, which is almost unused
+ */
+CodeCompletionResult::Availability CompletionProposalsBuilder::getAvailability(const CXCompletionResult &cxResult)
+{
+ CXCompletionString complStr = cxResult.CompletionString;
+ switch (clang_getCompletionAvailability(complStr)) {
+ case CXAvailability_Deprecated:
+ return CodeCompletionResult::Deprecated;
+
+ case CXAvailability_NotAvailable:
+ return CodeCompletionResult::NotAvailable;
+
+ case CXAvailability_NotAccessible:
+ return CodeCompletionResult::NotAccessible;
+
+ default:
+ return CodeCompletionResult::Available;
+ }
+}
+
+/**
+ * @return Start index of name, which is unused in Qt signal/slot signature
+ * @param text Text of Placeholder completion string chunk
+ */
+int CompletionProposalsBuilder::findNameInPlaceholder(const QString &text)
+{
+ bool firstIdPassed = false;
+ bool isInIdentifier = false;
+ int bracesCounter = 0;
+ int idStart = 0;
+
+ for (int i = 0, n = text.size(); i < n; ++i) {
+ const QChar ch = text[i];
+
+ if (ch == QLatin1Char(':')) {
+ firstIdPassed = false;
+ isInIdentifier = false;
+ }
+
+ if (ch == QLatin1Char('<') || ch == QLatin1Char('(')) {
+ if (isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
+ firstIdPassed = false;
+ ++bracesCounter;
+ isInIdentifier = false;
+ } else if (ch == QLatin1Char('>') || ch == QLatin1Char(')')) {
+ if (isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
+ firstIdPassed = false;
+ --bracesCounter;
+ isInIdentifier = false;
+ } else if (bracesCounter == 0) {
+ if (isInIdentifier) {
+ isInIdentifier = ch.isLetterOrNumber() || (ch == QLatin1Char('_'));
+ if (!isInIdentifier && text.mid(idStart, i - idStart) == QLatin1String("const"))
+ firstIdPassed = false;
+ } else if (ch.isLetter() || (ch == QLatin1Char('_'))) {
+ if (firstIdPassed)
+ return i;
+ isInIdentifier = true;
+ idStart = i;
+ firstIdPassed = true;
+ }
+ }
+ }
+ return text.size();
+}
+
+void CompletionProposalsBuilder::resetWithResult(const CXCompletionResult &cxResult)
+{
+ m_priority = clang_getCompletionPriority(cxResult.CompletionString);
+ m_resultKind = getKind(cxResult);
+ m_resultAvailability = getAvailability(cxResult);
+ m_hasParameters = false;
+ m_hint.clear();
+ m_text.clear();
+ m_snippet.clear();
+ m_comment.clear();
+ m_optionalChunks.clear();
+}
+
+/**
+ * @brief Appends completion proposal initialized with collected data
+ */
+void CompletionProposalsBuilder::finalize()
+{
+ // Fixes code completion: operator and destructor cases
+ if ((m_contexts & CXCompletionContext_DotMemberAccess)
+ || (m_contexts & CXCompletionContext_ArrowMemberAccess)
+ || (m_contexts & CXCompletionContext_AnyValue)) {
+ if (m_resultKind == CodeCompletionResult::DestructorCompletionKind)
+ m_priority *= PriorityFix_ExplicitDestructorCall;
+ else if (m_resultKind == CodeCompletionResult::FunctionCompletionKind
+ && m_text.startsWith(QLatin1String("operator")))
+ return;
+ }
+
+ CodeCompletionResult ccr(m_priority);
+ ccr.setCompletionKind(m_resultKind);
+ ccr.setAvailability(m_resultAvailability);
+ ccr.setHasParameters(m_hasParameters);
+ ccr.setHint(m_hint);
+ ccr.setText(m_text);
+ ccr.setSnippet(m_snippet);
+ m_results.append(ccr);
+}
+
+/**
+ * @brief Creates text, hint and snippet
+ *
+ * Text is just signature, e.g. 'length' for [NSString length] or 'respondsToSelector:'
+ * for [id respondsToSelector:(SEL)sel].
+ * Snippet is actual text, where any message parameter becames snippet part:
+ * 'respondsToSelector:$(SEL)sel$'.
+ * Hint consists of snippet preview and doxygen 'return' entry with returned type.
+ */
+void CompletionProposalsBuilder::concatChunksForObjectiveCMessage(const CXCompletionResult &cxResult)
+{
+ CXCompletionString cxString = cxResult.CompletionString;
+ const unsigned count = clang_getNumCompletionChunks(cxString);
+ unsigned index = 0;
+ QString hintPrefix;
+ if (cxResult.CursorKind == CXCursor_ObjCClassMethodDecl)
+ hintPrefix += QLatin1Char('+');
+ else
+ hintPrefix += QLatin1Char('-');
+ int indentBonus = 1;
+
+ bool addSpaceAtPrefixEnd = true;
+ for (; index < count; ++index) {
+ CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, index);
+ if (chunkKind == CXCompletionChunk_TypedText || chunkKind == CXCompletionChunk_Informative) {
+ break;
+ }
+ const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, index), false);
+ if (chunkKind == CXCompletionChunk_ResultType) {
+ hintPrefix += QLatin1String("(");
+ hintPrefix += Qt::escape(text);
+ hintPrefix += QLatin1String(") ");
+ indentBonus += 3 + text.length();
+ addSpaceAtPrefixEnd = false;
+ } else {
+ hintPrefix += Qt::escape(text);
+ indentBonus += text.length();
+ m_snippet += text;
+ }
+ }
+ if (addSpaceAtPrefixEnd) {
+ m_snippet += QLatin1Char(' ');
+ hintPrefix += QLatin1Char(' ');
+ indentBonus += 1;
+ }
+
+ m_hint += hintPrefix;
+
+ QList parts;
+ bool previousWasTypedText = false;
+ for (; index < count; ++index) {
+ CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, index);
+ const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, index), false);
+
+ switch (chunkKind) {
+ case CXCompletionChunk_TypedText:
+ if (previousWasTypedText)
+ parts.back().addToSignature(text);
+ else
+ parts.append(ObjCMessagePart(text, indentBonus));
+ m_snippet += text;
+ m_text += text;
+ break;
+ case CXCompletionChunk_Informative:
+ parts.append(ObjCMessagePart(text, indentBonus));
+ break;
+ case CXCompletionChunk_Text:
+ case CXCompletionChunk_LeftParen:
+ case CXCompletionChunk_RightParen:
+ case CXCompletionChunk_Comma:
+ case CXCompletionChunk_HorizontalSpace:
+ m_snippet += text;
+ parts.back().text += Qt::escape(text);
+ break;
+ case CXCompletionChunk_Placeholder:
+ appendSnippet(text);
+ parts.back().text += QLatin1String("");
+ parts.back().text += Qt::escape(text);
+ parts.back().text += QLatin1String("");
+ break;
+ case CXCompletionChunk_LeftAngle:
+ m_snippet += text;
+ parts.back().text += QLatin1String("<");
+ break;
+ case CXCompletionChunk_RightAngle:
+ m_snippet += text;
+ parts.back().text += QLatin1String(">");
+ break;
+ default:
+ break;
+ }
+
+ previousWasTypedText = (chunkKind == CXCompletionChunk_TypedText);
+ }
+
+ int indent = 0;
+ foreach (const ObjCMessagePart &part, parts)
+ indent = qMax(indent, part.signatureLen);
+ bool isFirstPart = true;
+ foreach (const ObjCMessagePart &part, parts) {
+ if (!isFirstPart)
+ m_hint += QLatin1String("
");
+ isFirstPart = false;
+ for (int i = 0; i < indent - part.signatureLen; ++i)
+ m_hint += QLatin1String(" ");
+ m_hint += part.text;
+ }
+}
+
+/**
+ * @brief Creates entries like 'MyClass', 'MyNamespace::', 'MyEnumClass::Value1'
+ */
+void CompletionProposalsBuilder::concatChunksForNestedName(const CXCompletionString &cxString)
+{
+ bool hasPlaceholder = false;
+ unsigned count = clang_getNumCompletionChunks(cxString);
+ for (unsigned i = 0; i < count; ++i) {
+ CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
+ QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
+
+ switch (chunkKind) {
+ case CXCompletionChunk_TypedText:
+ case CXCompletionChunk_Text:
+ m_text += text;
+ m_snippet += text;
+ m_hint += text;
+ break;
+
+ case CXCompletionChunk_LeftAngle:
+ case CXCompletionChunk_RightAngle:
+ case CXCompletionChunk_Comma:
+ case CXCompletionChunk_HorizontalSpace:
+ m_snippet += text;
+ m_hint += Qt::escape(text);
+ break;
+
+ case CXCompletionChunk_Placeholder:
+ hasPlaceholder = true;
+ appendSnippet(text);
+ appendHintBold(text);
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (!hasPlaceholder)
+ m_snippet.clear();
+}
+
+/**
+ * @brief Creates text, snippet and hint for snippet preview
+ *
+ * Text is copy of snippet without '$' marks.
+ * Hint also have 'return' doxygen entry if applicable (e.g. 'typeid...')
+ */
+void CompletionProposalsBuilder::concatChunksAsSnippet(const CXCompletionString &cxString)
+{
+ unsigned count = clang_getNumCompletionChunks(cxString);
+ for (unsigned i = 0; i < count; ++i) {
+ CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
+ const QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
+
+ switch (chunkKind) {
+ case CXCompletionChunk_ResultType:
+ attachResultTypeToComment(text);
+ break;
+
+ case CXCompletionChunk_Placeholder:
+ m_text += text;
+ appendSnippet(text);
+ appendHintBold(text);
+ break;
+ case CXCompletionChunk_LeftAngle:
+ m_snippet += text;
+ m_text += text;
+ m_hint += QLatin1String("<");
+ break;
+ case CXCompletionChunk_RightAngle:
+ m_snippet += text;
+ m_text += text;
+ m_hint += QLatin1String(">");
+ break;
+
+ case CXCompletionChunk_VerticalSpace:
+ m_snippet += QLatin1Char('\n');
+ m_text += QLatin1Char(' ');
+ m_hint += QLatin1String("
");
+ break;
+
+ default:
+ m_snippet += text;
+ m_text += text;
+ m_hint += text;
+ break;
+ }
+ }
+}
+
+/**
+ * @brief Creates short text and hint with details
+ *
+ * Text is just function or variable name. Hint also contains function signature
+ * or variable type.
+ */
+void CompletionProposalsBuilder::concatChunksOnlyTypedText(const CXCompletionString &cxString)
+{
+ bool previousChunkWasLParen = false;
+ bool isInsideTemplateSpec = false;
+
+ unsigned count = clang_getNumCompletionChunks(cxString);
+ for (unsigned i = 0; i < count; ++i) {
+ CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
+ QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
+
+ switch (chunkKind) {
+ case CXCompletionChunk_LeftParen:
+ case CXCompletionChunk_RightParen:
+ case CXCompletionChunk_Text:
+ case CXCompletionChunk_LeftAngle:
+ case CXCompletionChunk_RightAngle:
+ m_hint += Qt::escape(text);
+ break;
+
+ case CXCompletionChunk_HorizontalSpace:
+ case CXCompletionChunk_Comma:
+ if (isInsideTemplateSpec) {
+ m_snippet += text;
+ }
+ m_hint += Qt::escape(text);
+ break;
+
+ case CXCompletionChunk_Placeholder:
+ if (isInsideTemplateSpec) {
+ appendSnippet(text);
+ }
+ m_hint += Qt::escape(text);
+ break;
+
+ case CXCompletionChunk_TypedText:
+ m_text = text;
+ appendHintBold(text);
+ break;
+
+ case CXCompletionChunk_ResultType: {
+ m_hint += Qt::escape(text);
+ QChar last = text[text.size() - 1];
+ if (last != QLatin1Char('*') && last != QLatin1Char('&'))
+ m_hint += QLatin1Char(' ');
+ }
+ break;
+
+ case CXCompletionChunk_Informative:
+ if (text == QLatin1String(" const"))
+ m_hint += text;
+ break;
+
+ case CXCompletionChunk_Optional:
+ appendOptionalChunks(clang_getCompletionChunkCompletionString(cxString, i),
+ m_hint.size());
+ break;
+
+ default:
+ break;
+ }
+
+ if (chunkKind == CXCompletionChunk_RightParen && previousChunkWasLParen)
+ m_hasParameters = false;
+
+ if (chunkKind == CXCompletionChunk_LeftParen) {
+ previousChunkWasLParen = true;
+ m_hasParameters = true;
+ } else {
+ previousChunkWasLParen = false;
+ }
+
+ if (chunkKind == CXCompletionChunk_LeftAngle) {
+ m_snippet = m_text;
+ m_snippet += text;
+ isInsideTemplateSpec = true;
+ } else if (chunkKind == CXCompletionChunk_RightAngle) {
+ isInsideTemplateSpec = false;
+ m_snippet += text;
+ }
+ }
+}
+
+/**
+ * @brief Produces signal/slot signatures for 'connect' methods family
+ */
+void CompletionProposalsBuilder::concatSlotSignalSignature(const CXCompletionString &cxString)
+{
+ QString resultType;
+
+ unsigned count = clang_getNumCompletionChunks(cxString);
+ for (unsigned i = 0; i < count; ++i) {
+ CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
+ QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
+
+ switch (chunkKind) {
+ case CXCompletionChunk_Placeholder:
+ text.truncate(findNameInPlaceholder(text));
+ // fall-through
+ case CXCompletionChunk_TypedText:
+ case CXCompletionChunk_LeftParen:
+ case CXCompletionChunk_RightParen:
+ case CXCompletionChunk_Comma:
+ case CXCompletionChunk_Text:
+ m_text += text;
+ break;
+ case CXCompletionChunk_ResultType:
+ resultType += text;
+ resultType += QLatin1Char(' ');
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ const QString parent = Internal::getQString(clang_getCompletionParent(cxString, NULL));
+ if (m_resultKind == CodeCompletionResult::SlotCompletionKind)
+ m_hint += QObject::tr("Slot of %1, returns %2").arg(parent).arg(resultType);
+ else
+ m_hint += QObject::tr("Signal of %1, returns %2").arg(parent).arg(resultType);
+}
+
+/**
+ * @brief Stores optional part for further postprocessing in \a finalize()
+ * @param insertionIndex Index where to insert optional chunk into hint
+ */
+void CompletionProposalsBuilder::appendOptionalChunks(const CXCompletionString &cxString,
+ int insertionIndex)
+{
+ OptionalChunk chunk;
+ chunk.positionInHint = insertionIndex;
+
+ unsigned count = clang_getNumCompletionChunks(cxString);
+ for (unsigned i = 0; i < count; ++i) {
+ CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(cxString, i);
+ QString text = Internal::getQString(clang_getCompletionChunkText(cxString, i), false);
+
+ switch (chunkKind) {
+ case CXCompletionChunk_Placeholder:
+ chunk.hint += Qt::escape(text);
+ break;
+
+ case CXCompletionChunk_Comma:
+ chunk.hint += text;
+ chunk.hint += QLatin1Char(' ');
+ break;
+
+ case CXCompletionChunk_Optional:
+ m_optionalChunks.append(chunk);
+ appendOptionalChunks(clang_getCompletionChunkCompletionString(cxString, i),
+ insertionIndex + chunk.hint.size());
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ m_optionalChunks.append(chunk);
+}
+
+void CompletionProposalsBuilder::attachResultTypeToComment(const QString &resultType)
+{
+ if (resultType.isEmpty())
+ return;
+
+ if (!m_comment.isEmpty())
+ m_comment += QLatin1String("
");
+
+ m_comment += QLatin1String("@return ");
+ m_comment += resultType;
+}
+
+void CompletionProposalsBuilder::appendSnippet(const QString &text)
+{
+ m_snippet += QLatin1Char('$');
+ m_snippet += text;
+ m_snippet += QLatin1Char('$');
+}
+
+void CompletionProposalsBuilder::appendHintBold(const QString &text)
+{
+ m_hint += QLatin1String("");
+ m_hint += Qt::escape(text);
+ m_hint += QLatin1String("");
+}
+
+} // namespace ClangCodeModel
diff --git a/src/plugins/clangcodemodel/completionproposalsbuilder.h b/src/plugins/clangcodemodel/completionproposalsbuilder.h
new file mode 100644
index 00000000000..919fbd9c89b
--- /dev/null
+++ b/src/plugins/clangcodemodel/completionproposalsbuilder.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H
+#define CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H
+
+#include "clangcompleter.h"
+#include "clang_global.h"
+#include
+
+namespace ClangCodeModel {
+
+class CLANG_EXPORT CompletionProposalsBuilder
+{
+public:
+ CompletionProposalsBuilder(QList &results, quint64 contexts, bool isSignalSlotCompletion);
+ void operator ()(const CXCompletionResult &cxResult);
+
+private:
+ struct OptionalChunk {
+ int positionInHint;
+ QString hint;
+
+ OptionalChunk() : positionInHint(0) {}
+ };
+
+ static CodeCompletionResult::Kind getKind(const CXCompletionResult &cxResult);
+ static CodeCompletionResult::Availability getAvailability(const CXCompletionResult &cxResult);
+ static int findNameInPlaceholder(const QString &text);
+ void resetWithResult(const CXCompletionResult &cxResult);
+ void finalize();
+
+ void concatChunksForObjectiveCMessage(const CXCompletionResult &cxResult);
+ void concatChunksForNestedName(const CXCompletionString &cxString);
+ void concatChunksAsSnippet(const CXCompletionString &cxString);
+ void concatChunksOnlyTypedText(const CXCompletionString &cxString);
+ void concatSlotSignalSignature(const CXCompletionString &cxString);
+ void appendOptionalChunks(const CXCompletionString &cxString,
+ int insertionIndex);
+ void attachResultTypeToComment(const QString &text);
+
+ void appendSnippet(const QString &text);
+ void appendHintBold(const QString &text);
+
+ QList &m_results;
+ const quint64 m_contexts;
+ const bool m_isSignalSlotCompletion;
+
+ unsigned m_priority;
+ CodeCompletionResult::Kind m_resultKind;
+ CodeCompletionResult::Availability m_resultAvailability;
+ bool m_hasParameters;
+ QString m_hint;
+ QString m_text;
+ QString m_snippet;
+ QString m_comment;
+ QList m_optionalChunks;
+};
+
+} // namespace ClangCodeModel
+
+#endif // CLANGCODEMODEL_COMPLETIONPROPOSALSBUILDER_H
diff --git a/src/plugins/clangcodemodel/constants.h b/src/plugins/clangcodemodel/constants.h
new file mode 100644
index 00000000000..2699cbeca84
--- /dev/null
+++ b/src/plugins/clangcodemodel/constants.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CONSTANTS_H
+#define CONSTANTS_H
+
+#include
+#include
+
+namespace ClangCodeModel {
+namespace Constants {
+
+static const QLatin1Char kLParen('(');
+static const QLatin1Char kRParen(')');
+static const QLatin1Char kLBrace('{');
+static const QLatin1Char kRBrace('}');
+static const QLatin1Char kLBracket('[');
+static const QLatin1Char kRBracket(']');
+static const QLatin1Char kLABracket('<');
+static const QLatin1Char kRABracket('>');
+static const QLatin1Char kSemiColon(';');
+static const QLatin1Char kPound('#');
+static const QLatin1Char kColon(':');
+static const QLatin1Char kExclamation('!');
+static const QLatin1Char kSpace(' ');
+static const QLatin1Char kSlash('/');
+static const QLatin1Char kStar('*');
+static const QLatin1Char kDoubleQuote('"');
+static const QLatin1Char kNewLine('\n');
+static const QLatin1Char kHorizontalTab('\t');
+
+}
+}
+
+#endif // CONSTANTS_H
diff --git a/src/plugins/clangcodemodel/cppcreatemarkers.cpp b/src/plugins/clangcodemodel/cppcreatemarkers.cpp
new file mode 100644
index 00000000000..ebd162e7307
--- /dev/null
+++ b/src/plugins/clangcodemodel/cppcreatemarkers.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "clangutils.h"
+#include "cppcreatemarkers.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+
+static const bool DebugTiming = !qgetenv("QTC_CLANG_VERBOSE").isEmpty();
+
+using namespace ClangCodeModel;
+using namespace ClangCodeModel::Internal;
+using namespace CppTools;
+
+CreateMarkers *CreateMarkers::create(SemanticMarker::Ptr semanticMarker,
+ const QString &fileName,
+ const QStringList &options,
+ unsigned firstLine, unsigned lastLine,
+ FastIndexer *fastIndexer,
+ const Internal::PchInfo::Ptr &pchInfo)
+{
+ if (semanticMarker.isNull())
+ return 0;
+ else
+ return new CreateMarkers(semanticMarker, fileName, options, firstLine, lastLine, fastIndexer, pchInfo);
+}
+
+CreateMarkers::CreateMarkers(SemanticMarker::Ptr semanticMarker,
+ const QString &fileName,
+ const QStringList &options,
+ unsigned firstLine, unsigned lastLine,
+ FastIndexer *fastIndexer,
+ const Internal::PchInfo::Ptr &pchInfo)
+ : m_marker(semanticMarker)
+ , m_pchInfo(pchInfo)
+ , m_fileName(fileName)
+ , m_options(options)
+ , m_firstLine(firstLine)
+ , m_lastLine(lastLine)
+ , m_fastIndexer(fastIndexer)
+{
+ Q_ASSERT(!semanticMarker.isNull());
+
+ m_flushRequested = false;
+ m_flushLine = 0;
+
+ m_unsavedFiles = Utils::createUnsavedFiles(CppModelManagerInterface::instance()->workingCopy());
+}
+
+CreateMarkers::~CreateMarkers()
+{ }
+
+void CreateMarkers::run()
+{
+ QMutexLocker lock(m_marker->mutex());
+ if (isCanceled())
+ return;
+
+ m_options += QLatin1String("-fspell-checking");
+
+ QTime t;
+ if (DebugTiming) {
+ qDebug() << "*** Highlighting from" << m_firstLine << "to" << m_lastLine << "of" << m_fileName;
+ qDebug() << "***** Options: " << m_options.join(QLatin1String(" "));
+ t.start();
+ }
+
+ m_usages.clear();
+ m_marker->setFileName(m_fileName);
+ m_marker->setCompilationOptions(m_options);
+
+ m_marker->reparse(m_unsavedFiles);
+
+ if (DebugTiming)
+ qDebug() << "*** Reparse for highlighting took" << t.elapsed() << "ms.";
+
+ m_pchInfo.clear();
+
+ typedef CPlusPlus::Document::DiagnosticMessage OtherDiagnostic;
+ QList msgs;
+ foreach (const ClangCodeModel::Diagnostic &d, m_marker->diagnostics()) {
+ if (DebugTiming)
+ qDebug() << d.severityAsString() << d.location() << d.spelling();
+
+ if (d.location().fileName() != m_marker->fileName())
+ continue;
+
+ // TODO: retrieve fix-its for this diagnostic
+
+ int level;
+ switch (d.severity()) {
+ case Diagnostic::Fatal: level = OtherDiagnostic::Fatal; break;
+ case Diagnostic::Error: level = OtherDiagnostic::Error; break;
+ case Diagnostic::Warning: level = OtherDiagnostic::Warning; break;
+ default: continue;
+ }
+ msgs.append(OtherDiagnostic(level, d.location().fileName(), d.location().line(),
+ d.location().column(), d.spelling(), d.length()));
+ }
+ if (isCanceled()) {
+ reportFinished();
+ return;
+ }
+
+ CppModelManagerInterface *mmi = CppModelManagerInterface::instance();
+ static const QString key = QLatin1String("ClangCodeModel.Diagnostics");
+ mmi->setExtraDiagnostics(m_marker->fileName(), key, msgs);
+#if CINDEX_VERSION_MINOR >= 21
+ mmi->setIfdefedOutBlocks(m_marker->fileName(), m_marker->ifdefedOutBlocks());
+#endif
+
+ if (isCanceled()) {
+ reportFinished();
+ return;
+ }
+
+ QList markers = m_marker->sourceMarkersInRange(m_firstLine, m_lastLine);
+ foreach (const ClangCodeModel::SourceMarker &m, markers)
+ addUse(SourceMarker(m.location().line(), m.location().column(), m.length(), m.kind()));
+
+ if (isCanceled()) {
+ reportFinished();
+ return;
+ }
+
+ flush();
+ reportFinished();
+
+ if (DebugTiming) {
+ qDebug() << "*** Highlighting took" << t.elapsed() << "ms in total.";
+ t.restart();
+ }
+
+ if (m_fastIndexer)
+ m_fastIndexer->indexNow(m_marker->unit());
+
+ if (DebugTiming)
+ qDebug() << "*** Fast re-indexing took" << t.elapsed() << "ms in total.";
+}
+
+void CreateMarkers::addUse(const SourceMarker &marker)
+{
+// if (! enclosingFunctionDefinition()) {
+ if (m_usages.size() >= 100) {
+ if (m_flushRequested && marker.line != m_flushLine)
+ flush();
+ else if (! m_flushRequested) {
+ m_flushRequested = true;
+ m_flushLine = marker.line;
+ }
+ }
+// }
+
+ m_usages.append(marker);
+}
+
+void CreateMarkers::flush()
+{
+ m_flushRequested = false;
+ m_flushLine = 0;
+
+ if (m_usages.isEmpty())
+ return;
+
+ reportResults(m_usages);
+ m_usages.clear();
+}
diff --git a/src/plugins/clangcodemodel/cppcreatemarkers.h b/src/plugins/clangcodemodel/cppcreatemarkers.h
new file mode 100644
index 00000000000..9f42f47c32f
--- /dev/null
+++ b/src/plugins/clangcodemodel/cppcreatemarkers.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CPPCREATEMARKERS_H
+#define CPPCREATEMARKERS_H
+
+#include "fastindexer.h"
+#include "sourcemarker.h"
+#include "semanticmarker.h"
+#include "pchinfo.h"
+
+#include
+
+#include
+#include
+#include
+
+namespace ClangCodeModel {
+
+class CreateMarkers:
+ public QObject,
+ public QRunnable,
+ public QFutureInterface
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(CreateMarkers)
+
+public:
+ virtual ~CreateMarkers();
+
+ virtual void run();
+
+ typedef TextEditor::HighlightingResult SourceMarker;
+
+ typedef QFuture Future;
+
+ Future start()
+ {
+ this->setRunnable(this);
+ this->reportStarted();
+ Future future = this->future();
+ QThreadPool::globalInstance()->start(this, QThread::LowestPriority);
+ return future;
+ }
+
+ static CreateMarkers *create(ClangCodeModel::SemanticMarker::Ptr semanticMarker,
+ const QString &fileName,
+ const QStringList &options,
+ unsigned firstLine, unsigned lastLine,
+ Internal::FastIndexer *fastIndexer,
+ const Internal::PchInfo::Ptr &pchInfo);
+
+ void addUse(const SourceMarker &marker);
+ void flush();
+
+protected:
+ CreateMarkers(ClangCodeModel::SemanticMarker::Ptr semanticMarker,
+ const QString &fileName, const QStringList &options,
+ unsigned firstLine, unsigned lastLine,
+ Internal::FastIndexer *fastIndexer,
+ const Internal::PchInfo::Ptr &pchInfo);
+
+private:
+ ClangCodeModel::SemanticMarker::Ptr m_marker;
+ Internal::PchInfo::Ptr m_pchInfo;
+ QString m_fileName;
+ QStringList m_options;
+ unsigned m_firstLine;
+ unsigned m_lastLine;
+ Internal::FastIndexer *m_fastIndexer;
+ QVector m_usages;
+ bool m_flushRequested;
+ unsigned m_flushLine;
+
+ ClangCodeModel::Internal::UnsavedFiles m_unsavedFiles;
+};
+
+} // namespace ClangCodeModel
+
+#endif // CPPCREATEMARKERS_H
diff --git a/src/plugins/clangcodemodel/cxprettyprinter.cpp b/src/plugins/clangcodemodel/cxprettyprinter.cpp
new file mode 100644
index 00000000000..1b954462cdf
--- /dev/null
+++ b/src/plugins/clangcodemodel/cxprettyprinter.cpp
@@ -0,0 +1,550 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "cxprettyprinter.h"
+#include "utils_p.h"
+#include "cxraii.h"
+#include
+
+using namespace ClangCodeModel;
+using namespace ClangCodeModel::Internal;
+
+CXPrettyPrinter::CXPrettyPrinter()
+ : m_indent(0)
+{
+}
+
+QString CXPrettyPrinter::toString(CXCompletionChunkKind kind) const
+{
+ switch (kind) {
+ case CXCompletionChunk_Optional:
+ return QLatin1String("Optional");
+ case CXCompletionChunk_TypedText:
+ return QLatin1String("TypedText");
+ case CXCompletionChunk_Text:
+ return QLatin1String("Text");
+ case CXCompletionChunk_Placeholder:
+ return QLatin1String("Placeholder");
+ case CXCompletionChunk_Informative:
+ return QLatin1String("Informative");
+ case CXCompletionChunk_CurrentParameter:
+ return QLatin1String("CurrentParameter");
+ case CXCompletionChunk_LeftParen:
+ return QLatin1String("LeftParen");
+ case CXCompletionChunk_RightParen:
+ return QLatin1String("RightParen");
+ case CXCompletionChunk_LeftBracket:
+ return QLatin1String("LeftBracket");
+ case CXCompletionChunk_RightBracket:
+ return QLatin1String("RightBracket");
+ case CXCompletionChunk_LeftBrace:
+ return QLatin1String("LeftBrace");
+ case CXCompletionChunk_RightBrace:
+ return QLatin1String("RightBrace");
+ case CXCompletionChunk_LeftAngle:
+ return QLatin1String("LeftAngle");
+ case CXCompletionChunk_RightAngle:
+ return QLatin1String("RightAngle");
+ case CXCompletionChunk_Comma:
+ return QLatin1String("Comma");
+ case CXCompletionChunk_ResultType:
+ return QLatin1String("ResultType");
+ case CXCompletionChunk_Colon:
+ return QLatin1String("Colon");
+ case CXCompletionChunk_SemiColon:
+ return QLatin1String("SemiColon");
+ case CXCompletionChunk_Equal:
+ return QLatin1String("Equal");
+ case CXCompletionChunk_HorizontalSpace:
+ return QLatin1String("HorizontalSpace");
+ case CXCompletionChunk_VerticalSpace:
+ return QLatin1String("VerticalSpace");
+ default:
+ return QLatin1String("");
+ }
+}
+
+QString CXPrettyPrinter::toString(CXAvailabilityKind kind) const
+{
+ switch (kind) {
+ case CXAvailability_Available:
+ return QLatin1String("Available");
+ case CXAvailability_Deprecated:
+ return QLatin1String("Deprecated");
+ case CXAvailability_NotAccessible:
+ return QLatin1String("NotAccessible");
+ case CXAvailability_NotAvailable:
+ return QLatin1String("NotAvailable");
+ default:
+ return QLatin1String("");
+ }
+}
+
+QString CXPrettyPrinter::toString(CXCursorKind kind) const
+{
+ return getQString(clang_getCursorKindSpelling(kind));
+}
+
+QString CXPrettyPrinter::toString(CXDiagnosticSeverity severity) const
+{
+ switch (severity)
+ {
+ case CXDiagnostic_Ignored:
+ return QLatin1String("Ignored");
+ case CXDiagnostic_Note:
+ return QLatin1String("Note");
+ case CXDiagnostic_Warning:
+ return QLatin1String("Warning");
+ case CXDiagnostic_Error:
+ return QLatin1String("Error");
+ case CXDiagnostic_Fatal:
+ return QLatin1String("Fatal");
+ default:
+ return QLatin1String("");
+ }
+}
+
+QString CXPrettyPrinter::jsonForCompletionMeta(CXCodeCompleteResults *results)
+{
+ QString json;
+ m_printed.swap(json);
+ m_indent = 0;
+
+ m_printed += QLatin1String("CXCodeCompleteResults {");
+ m_indent += 4;
+
+ CXCursorKind containerKind = clang_codeCompleteGetContainerKind(results, NULL);
+ writeLineEnd();
+ m_printed += QLatin1String("'container CursorKind': ");
+ m_printed += toString(containerKind);
+ m_printed += QLatin1Char(',');
+
+ QString containerUSR(Internal::getQString(clang_codeCompleteGetContainerUSR(results)));
+ if (!containerUSR.isEmpty()) {
+ writeLineEnd();
+ m_printed += QLatin1String("'container USR': ");
+ m_printed += containerUSR;
+ m_printed += QLatin1Char(',');
+ }
+
+ QString objCSelector(Internal::getQString(clang_codeCompleteGetObjCSelector(results)));
+ if (!objCSelector.isEmpty()) {
+ writeLineEnd();
+ m_printed += QLatin1String("'Objective-C selector': ");
+ m_printed += objCSelector;
+ m_printed += QLatin1Char(',');
+ }
+
+ writeLineEnd();
+ m_printed += QLatin1String("'contexts': [");
+ m_indent += 4;
+ writeCompletionContexts(results);
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1Char(']');
+
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1Char('}');
+
+ m_printed.swap(json);
+ return json;
+}
+
+QString CXPrettyPrinter::jsonForCompletionString(const CXCompletionString &string)
+{
+ QString json;
+ m_printed.swap(json);
+ m_indent = 0;
+
+ m_printed += QLatin1String("CXCompletionString: ");
+ writeCompletionStringJson(string);
+
+ m_printed.swap(json);
+ return json;
+}
+
+QString CXPrettyPrinter::jsonForCompletion(const CXCompletionResult &result)
+{
+ QString json;
+ m_printed.swap(json);
+ m_indent = 4;
+
+ m_printed += QLatin1String("CXCompletionResult: {\n"
+ " CompletionString: ");
+ writeCompletionStringJson(result.CompletionString);
+ m_printed += QLatin1Char('\n');
+
+ m_printed += QLatin1String(" CursorKind: ");
+ m_printed += toString(result.CursorKind);
+ m_printed += QLatin1String(";\n}");
+
+ m_printed.swap(json);
+ return json;
+}
+
+/**
+ * @brief CXPrettyPrinter::jsonForDiagnsotic
+ * @param diagnostic
+ * @return
+ *
+ * List of used clang-c API calls:
+ * CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
+ * CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic);
+ * CXString clang_getDiagnosticOption(CXDiagnostic Diag,
+ * CXString *Disable);
+ * unsigned clang_getDiagnosticCategory(CXDiagnostic);
+ * CXString clang_getDiagnosticCategoryText(CXDiagnostic);
+ * unsigned clang_getDiagnosticNumRanges(CXDiagnostic);
+ * CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic,
+ * unsigned Range);
+ * unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic);
+ * CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic,
+ * unsigned FixIt,
+ * CXSourceRange *ReplacementRange);
+ */
+QString CXPrettyPrinter::jsonForDiagnsotic(const CXDiagnostic &diagnostic)
+{
+ QString json;
+ m_printed.swap(json);
+ m_indent = 0;
+
+ m_printed += QLatin1String("CXDiagnostic: ");
+ writeDiagnosticJson(diagnostic);
+
+ m_printed.swap(json);
+ return json;
+}
+
+void CXPrettyPrinter::writeCompletionContexts(CXCodeCompleteResults *results)
+{
+ quint64 contexts = clang_codeCompleteGetContexts(results);
+ QStringList lines;
+
+ if (contexts & CXCompletionContext_AnyType)
+ lines << QLatin1String("'any type'");
+ if (contexts & CXCompletionContext_AnyValue)
+ lines << QLatin1String("'any value'");
+ if (contexts & CXCompletionContext_ObjCObjectValue)
+ lines << QLatin1String("'Objective-C object'");
+ if (contexts & CXCompletionContext_ObjCSelectorValue)
+ lines << QLatin1String("'Objective-C selector'");
+ if (contexts & CXCompletionContext_CXXClassTypeValue)
+ lines << QLatin1String("'C++ class'");
+ if (contexts & CXCompletionContext_DotMemberAccess)
+ lines << QLatin1String("'. member access'");
+ if (contexts & CXCompletionContext_ArrowMemberAccess)
+ lines << QLatin1String("'-> member access'");
+ if (contexts & CXCompletionContext_ObjCPropertyAccess)
+ lines << QLatin1String("'. Objective-C property access'");
+ if (contexts & CXCompletionContext_EnumTag)
+ lines << QLatin1String("'enum tag'");
+ if (contexts & CXCompletionContext_UnionTag)
+ lines << QLatin1String("'union tag'");
+ if (contexts & CXCompletionContext_StructTag)
+ lines << QLatin1String("'struct tag'");
+ if (contexts & CXCompletionContext_ClassTag)
+ lines << QLatin1String("'C++ class tag'");
+ if (contexts & CXCompletionContext_Namespace)
+ lines << QLatin1String("'namespace tag'");
+ if (contexts & CXCompletionContext_NestedNameSpecifier)
+ lines << QLatin1String("'C++ nested name specifier'");
+ if (contexts & CXCompletionContext_ObjCInterface)
+ lines << QLatin1String("'Objective-C interface'");
+ if (contexts & CXCompletionContext_ObjCProtocol)
+ lines << QLatin1String("'Objective-C protocol'");
+ if (contexts & CXCompletionContext_ObjCCategory)
+ lines << QLatin1String("'Objective-C category'");
+ if (contexts & CXCompletionContext_ObjCInstanceMessage)
+ lines << QLatin1String("'Objective-C instance message'");
+ if (contexts & CXCompletionContext_ObjCClassMessage)
+ lines << QLatin1String("'Objective-C class message'");
+ if (contexts & CXCompletionContext_ObjCSelectorName)
+ lines << QLatin1String("'Objective-C selector name'");
+ if (contexts & CXCompletionContext_MacroName)
+ lines << QLatin1String("'macro name'");
+ if (contexts & CXCompletionContext_NaturalLanguage)
+ lines << QLatin1String("'natural language'");
+
+ foreach (const QString &line, lines) {
+ writeLineEnd();
+ m_printed += line + QLatin1String(",");
+ }
+}
+
+void CXPrettyPrinter::writeCompletionStringJson(const CXCompletionString &string)
+{
+ m_printed += QLatin1Char('{');
+ writeLineEnd();
+
+ // availability
+ m_printed += QLatin1String("availability: ");
+ m_printed += toString(clang_getCompletionAvailability(string));
+ m_printed += QLatin1Char(';');
+ writeLineEnd();
+
+ // priority
+ m_printed += QLatin1String("priority: ");
+ m_printed += QString::number(clang_getCompletionPriority(string));
+ m_printed += QLatin1Char(';');
+ writeLineEnd();
+
+ // parent
+ m_printed += QLatin1String("parent: \'");
+ m_printed += getQString(clang_getCompletionParent(string, NULL));
+ m_printed += QLatin1String("\';");
+ writeLineEnd();
+
+ // chunks
+ m_printed += QLatin1String("chunks: [");
+ m_indent += 4;
+ unsigned numChunks = clang_getNumCompletionChunks(string);
+ for (unsigned i = 0; i < numChunks; ++i) {
+ writeLineEnd();
+ writeCompletionChunkJson(string, i);
+ }
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1Char(']');
+ writeLineEnd();
+
+ // annotation
+ m_printed += QLatin1String("annotations: [");
+ m_indent += 4;
+ unsigned numAnns = clang_getCompletionNumAnnotations(string);
+ for (unsigned i = 0; i < numAnns; ++i) {
+ writeLineEnd();
+ writeCompletionAnnotationJson(string, i);
+ }
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1Char(']');
+ writeLineEnd();
+
+ m_printed += QLatin1Char('}');
+}
+
+void CXPrettyPrinter::writeCompletionChunkJson(const CXCompletionString &string, unsigned i)
+{
+ QString text = getQString(clang_getCompletionChunkText(string, i));
+ QString kind = toString(clang_getCompletionChunkKind(string, i));
+ CXCompletionString optional = clang_getCompletionChunkCompletionString(string, i);
+
+ m_printed += kind;
+ m_printed += QLatin1String(": ");
+ if (!text.isEmpty()) {
+ m_printed += QLatin1Char('\'');
+ m_printed += text;
+ m_printed += QLatin1Char('\'');
+ }
+ if (optional != NULL) {
+ if (!text.isEmpty())
+ m_printed += QLatin1String(", ");
+ m_indent += 4;
+ writeCompletionStringJson(optional);
+ m_indent -= 4;
+ }
+}
+
+void CXPrettyPrinter::writeCompletionAnnotationJson(const CXCompletionString &string, unsigned i)
+{
+ m_printed += QLatin1Char('\'');
+ m_printed += getQString(clang_getCompletionAnnotation(string, i));
+ m_printed += QLatin1Char('\'');
+}
+
+void CXPrettyPrinter::writeDiagnosticJson(const CXDiagnostic &diag)
+{
+ m_printed += QLatin1String("{");
+ m_indent += 4;
+ writeLineEnd();
+
+ // message
+ m_printed += QLatin1Char('\'');
+ m_printed += getQString(clang_formatDiagnostic(diag, /*options*/ 0));
+ m_printed += QLatin1Char('\'');
+ writeLineEnd();
+
+ // severity
+ m_printed += QLatin1String("severity: ");
+ m_printed += toString(clang_getDiagnosticSeverity(diag));
+ writeLineEnd();
+
+ // location
+ m_printed += QLatin1String("location: ");
+ writeLocationJson(clang_getDiagnosticLocation(diag));
+ writeLineEnd();
+
+ // fix-its
+ unsigned numFixIts = clang_getDiagnosticNumFixIts(diag);
+ if (numFixIts > 0) {
+ m_printed += QLatin1String("FixIts: [");
+ writeLineEnd();
+ for (unsigned i = 0; i < numFixIts; ++i) {
+ writeFixItJson(diag, i);
+ writeLineEnd();
+ }
+ m_printed += QLatin1String("]");
+ writeLineEnd();
+ }
+
+ // clang CLI options
+ CXString cxDisabler;
+ QString enabler = getQString(clang_getDiagnosticOption(diag, &cxDisabler));
+ QString disabler = getQString(cxDisabler);
+ if (!enabler.isEmpty()) {
+ m_printed += QLatin1String("enabledBy: \'");
+ m_printed += enabler;
+ m_printed += QLatin1String("';");
+ writeLineEnd();
+ }
+ if (!disabler.isEmpty()) {
+ m_printed += QLatin1String("disabledBy: \'");
+ m_printed += disabler;
+ m_printed += QLatin1String("';");
+ writeLineEnd();
+ }
+
+ // diagnostic category
+ m_printed += QLatin1String("category: \'");
+ m_printed += getQString(clang_getDiagnosticCategoryText(diag));
+ m_printed += QLatin1String("';");
+
+ // ranges
+ unsigned numRanges = clang_getDiagnosticNumRanges(diag);
+ if (numRanges > 0) {
+ writeLineEnd();
+ m_printed += QLatin1String("ranges: [");
+ m_indent += 4;
+ for (unsigned i = 0; i < numRanges; ++i) {
+ writeLineEnd();
+ writeRangeJson(clang_getDiagnosticRange(diag, i));
+ }
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1String("]");
+ }
+
+ // children
+ CXDiagnosticSet set(clang_getChildDiagnostics(diag));
+ unsigned numChildren = clang_getNumDiagnosticsInSet(set);
+ if (numChildren > 0) {
+ writeLineEnd();
+ m_printed += QLatin1String("children: [");
+ m_indent += 4;
+ for (unsigned i = 0; i < numChildren; ++i) {
+ writeLineEnd();
+ ScopedCXDiagnostic child(clang_getDiagnosticInSet(set, i));
+ writeDiagnosticJson(child);
+ }
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1String("]");
+ }
+
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1String("}");
+}
+
+void CXPrettyPrinter::writeFixItJson(const CXDiagnostic &diag, unsigned i)
+{
+ CXSourceRange range; // half-open range [a, b)
+ QString text = getQString(clang_getDiagnosticFixIt(diag, i, &range));
+
+ m_printed += QLatin1String("{ newText: ");
+ m_printed += QLatin1String("\'");
+ m_printed += text;
+ m_printed += QLatin1String("\', range: ");
+ writeRangeJson(range);
+ m_printed += QLatin1String("}");
+}
+
+void CXPrettyPrinter::writeRangeJson(const CXSourceRange &range)
+{
+ SourceLocation start = getSpellingLocation(clang_getRangeStart(range));
+ SourceLocation end = getSpellingLocation(clang_getRangeEnd(range));
+
+ m_printed += QLatin1Char('{');
+ m_indent += 4;
+ writeLineEnd();
+
+ m_printed += QLatin1String("file: \'");
+ m_printed += start.fileName();
+ m_printed += QLatin1String("\',");
+ writeLineEnd();
+
+ m_printed += QLatin1String("from: {");
+ m_printed += QString::number(start.line());
+ m_printed += QLatin1String(", ");
+ m_printed += QString::number(start.column());
+ m_printed += QLatin1String("},");
+
+ m_printed += QLatin1String("to: {");
+ m_printed += QString::number(end.line());
+ m_printed += QLatin1String(", ");
+ m_printed += QString::number(end.column());
+ m_printed += QLatin1Char('}');
+
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1Char('}');
+}
+
+void CXPrettyPrinter::writeLocationJson(const CXSourceLocation &location)
+{
+ SourceLocation loc = getSpellingLocation(location);
+ m_printed += QLatin1Char('{');
+ m_indent += 4;
+ writeLineEnd();
+
+ m_printed += QLatin1String("file: \'");
+ m_printed += loc.fileName();
+ m_printed += QLatin1String("\',");
+ writeLineEnd();
+
+ m_printed += QLatin1String("line: ");
+ m_printed += QString::number(loc.line());
+ m_printed += QLatin1String(",");
+ writeLineEnd();
+
+ m_printed += QLatin1String("column: ");
+ m_printed += QString::number(loc.column());
+
+ m_indent -= 4;
+ writeLineEnd();
+ m_printed += QLatin1String("}");
+}
+
+void CXPrettyPrinter::writeLineEnd()
+{
+ m_printed += QLatin1Char('\n');
+ for (int i = 0; i < m_indent; ++i)
+ m_printed += QLatin1Char(' ');
+}
diff --git a/src/plugins/clangcodemodel/cxprettyprinter.h b/src/plugins/clangcodemodel/cxprettyprinter.h
new file mode 100644
index 00000000000..2143181dac0
--- /dev/null
+++ b/src/plugins/clangcodemodel/cxprettyprinter.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CXPRETTYPRINTER_H
+#define CXPRETTYPRINTER_H
+
+#include
+#include
+
+namespace ClangCodeModel {
+namespace Internal {
+
+class CXPrettyPrinter
+{
+public:
+ CXPrettyPrinter();
+
+ QString toString(CXCompletionChunkKind kind) const;
+ QString toString(CXAvailabilityKind kind) const;
+ QString toString(CXCursorKind kind) const;
+ QString toString(CXDiagnosticSeverity severity) const;
+
+ QString jsonForCompletionMeta(CXCodeCompleteResults *results);
+ QString jsonForCompletionString(const CXCompletionString &string);
+ QString jsonForCompletion(const CXCompletionResult &result);
+ QString jsonForDiagnsotic(const CXDiagnostic &diagnostic);
+
+private:
+ int m_indent;
+ QString m_printed;
+
+ void writeCompletionContexts(CXCodeCompleteResults *results);
+ void writeCompletionStringJson(const CXCompletionString &string);
+ void writeCompletionChunkJson(const CXCompletionString &string, unsigned i);
+ void writeCompletionAnnotationJson(const CXCompletionString &string, unsigned i);
+
+ void writeDiagnosticJson(const CXDiagnostic &diag);
+ void writeFixItJson(const CXDiagnostic &diag, unsigned i);
+
+ void writeRangeJson(const CXSourceRange &range);
+ void writeLocationJson(const CXSourceLocation &location);
+
+ void writeLineEnd();
+};
+
+} // namespace Internal
+} // namespace ClangCodeModel
+
+#endif // CXPRETTYPRINTER_H
diff --git a/src/plugins/clangcodemodel/cxraii.h b/src/plugins/clangcodemodel/cxraii.h
new file mode 100644
index 00000000000..9461bb8dc12
--- /dev/null
+++ b/src/plugins/clangcodemodel/cxraii.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CXRAII_H
+#define CXRAII_H
+
+#include
+
+// Simple RAII types for their CX correspondings
+
+namespace ClangCodeModel {
+namespace Internal {
+
+template
+struct ScopedCXType
+{
+protected:
+ typedef void (*DisposeFunction)(CXType_T);
+
+ ScopedCXType(DisposeFunction f)
+ : m_cx(0), m_disposeFunction(f)
+ {}
+ ScopedCXType(const CXType_T &cx, DisposeFunction f)
+ : m_cx(cx) , m_disposeFunction(f)
+ {}
+
+public:
+ ~ScopedCXType()
+ {
+ dispose();
+ }
+
+ operator CXType_T() const { return m_cx; }
+ bool operator!() const { return !m_cx; }
+ bool isNull() const { return !m_cx; }
+ void reset(const CXType_T &cx)
+ {
+ dispose();
+ m_cx = cx;
+ }
+
+private:
+ ScopedCXType(const ScopedCXType &);
+ const ScopedCXType &operator=(const ScopedCXType &);
+
+ void dispose()
+ {
+ if (m_cx)
+ m_disposeFunction(m_cx);
+ }
+
+ CXType_T m_cx;
+ DisposeFunction m_disposeFunction;
+};
+
+struct ScopedCXIndex : ScopedCXType
+{
+ ScopedCXIndex()
+ : ScopedCXType(&clang_disposeIndex)
+ {}
+ ScopedCXIndex(const CXIndex &index)
+ : ScopedCXType(index, &clang_disposeIndex)
+ {}
+};
+
+struct ScopedCXTranslationUnit : ScopedCXType
+{
+ ScopedCXTranslationUnit()
+ : ScopedCXType(&clang_disposeTranslationUnit)
+ {}
+ ScopedCXTranslationUnit(const CXTranslationUnit &unit)
+ : ScopedCXType(unit, &clang_disposeTranslationUnit)
+ {}
+};
+
+struct ScopedCXDiagnostic : ScopedCXType
+{
+ ScopedCXDiagnostic()
+ : ScopedCXType(&clang_disposeDiagnostic)
+ {}
+ ScopedCXDiagnostic(const CXDiagnostic &diagnostic)
+ : ScopedCXType(diagnostic, &clang_disposeDiagnostic)
+ {}
+};
+
+struct ScopedCXDiagnosticSet : ScopedCXType
+{
+ ScopedCXDiagnosticSet()
+ : ScopedCXType(&clang_disposeDiagnosticSet)
+ {}
+ ScopedCXDiagnosticSet(const CXDiagnostic &diagnostic)
+ : ScopedCXType(diagnostic, &clang_disposeDiagnosticSet)
+ {}
+};
+
+struct ScopedCXCodeCompleteResults : ScopedCXType
+{
+ ScopedCXCodeCompleteResults()
+ : ScopedCXType(&clang_disposeCodeCompleteResults)
+ {}
+ ScopedCXCodeCompleteResults(CXCodeCompleteResults *results)
+ : ScopedCXType(results, &clang_disposeCodeCompleteResults)
+ {}
+
+ unsigned size() const
+ {
+ return static_cast(*this)->NumResults;
+ }
+
+ const CXCompletionResult &completionAt(unsigned i)
+ {
+ return static_cast(*this)->Results[i];
+ }
+};
+
+} // Internal
+} // ClangCodeModel
+
+#endif // CXRAII_H
diff --git a/src/plugins/clangcodemodel/dependencygraph.cpp b/src/plugins/clangcodemodel/dependencygraph.cpp
new file mode 100644
index 00000000000..f0aadd66920
--- /dev/null
+++ b/src/plugins/clangcodemodel/dependencygraph.cpp
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "dependencygraph.h"
+
+#include
+
+using namespace ClangCodeModel;
+using namespace Internal;
+
+DependencyGraph::DependencyGraph()
+{
+ m_includeTracker.setResolutionMode(IncludeTracker::EveryMatchResolution);
+}
+
+DependencyGraph::~DependencyGraph()
+{
+ discard();
+}
+
+void DependencyGraph::cancel()
+{
+ if (m_computeWatcher.isRunning()) {
+ m_computeWatcher.cancel();
+ m_computeWatcher.waitForFinished();
+ }
+}
+
+void DependencyGraph::addFile(const QString &fileName, const QStringList &compilationOptions)
+{
+ cancel();
+
+ m_files.append(qMakePair(fileName, compilationOptions));
+}
+
+QFuture DependencyGraph::compute()
+{
+ QFuture future = QtConcurrent::run(this, &DependencyGraph::computeCore);
+ m_computeWatcher.setFuture(future);
+ return future;
+}
+
+void DependencyGraph::computeCore()
+{
+ for (int i = 0; i < m_files.size(); ++i) {
+ if (m_computeWatcher.isCanceled())
+ break;
+
+ const QPair &p = m_files.at(i);
+ const QString ¤tFile = p.first;
+ const QStringList &options = p.second;
+ const QPair &v = findVertex(currentFile);
+ if (!v.first)
+ processIncludes(insertVertex(currentFile), options);
+ }
+
+ emit dependencyGraphAvailable();
+}
+
+void DependencyGraph::processIncludes(NodeRefSetIt currentIt,
+ const QStringList &compilationOptions)
+{
+ const QString ¤tFile = currentIt.key();
+ const QStringList &includes = m_includeTracker.directIncludes(currentFile, compilationOptions);
+ foreach (const QString &include, includes) {
+ if (m_computeWatcher.isCanceled())
+ return;
+
+ QPair v = findVertex(include);
+ if (!v.first) {
+ v.second = insertVertex(include);
+ processIncludes(v.second, compilationOptions);
+ }
+ insertEdge(currentIt, v.second);
+ }
+}
+
+namespace {
+
+struct SimpleVisitor
+{
+ bool acceptFile(const QString &fileName)
+ {
+ m_allFiles.append(fileName);
+ return false;
+ }
+
+ QStringList m_allFiles;
+};
+
+}
+
+QStringList DependencyGraph::collectDependencies(const QString &referenceFile,
+ DependencyRole role) const
+{
+ SimpleVisitor visitor;
+ collectDependencies(referenceFile, role, &visitor);
+
+ return visitor.m_allFiles;
+}
+
+bool DependencyGraph::hasDependency(const QString &referenceFile, DependencyRole role) const
+{
+ QPair v = findVertex(referenceFile);
+ if (!v.first)
+ return false;
+
+ NodeListIt nodeIt = v.second.value();
+
+ if (role == FilesDirectlyIncludedBy || role == FilesIncludedBy)
+ return nodeIt->m_out != 0;
+
+ return nodeIt->m_in != 0;
+}
+
+void DependencyGraph::discard()
+{
+ cancel();
+
+ for (NodeListIt it = m_nodes.begin(); it != m_nodes.end(); ++it) {
+ deleteAdjacencies(it->m_out);
+ deleteAdjacencies(it->m_in);
+ }
+ m_nodes.clear();
+ m_nodesRefs.clear();
+ m_files.clear();
+}
+
+
+DependencyGraph::Node::Node(const QString &fileName)
+ : m_fileName(fileName)
+ , m_out(0)
+ , m_in(0)
+{}
+
+DependencyGraph::AdjacencyNode::AdjacencyNode(NodeListIt it)
+ : m_next(0)
+ , m_nodeIt(it)
+{}
+
+QPair DependencyGraph::findVertex(const QString &s) const
+{
+ bool found = false;
+ NodeRefSetIt it = const_cast(m_nodesRefs).find(s);
+ if (it != m_nodesRefs.end())
+ found = true;
+ return qMakePair(found, it);
+}
+
+DependencyGraph::NodeRefSetIt DependencyGraph::insertVertex(const QString &s)
+{
+ Q_ASSERT(m_nodesRefs.find(s) == m_nodesRefs.end());
+
+ m_nodes.append(Node(s));
+ return m_nodesRefs.insert(s, m_nodes.end() - 1);
+}
+
+void DependencyGraph::insertEdge(DependencyGraph::NodeRefSetIt fromIt,
+ DependencyGraph::NodeRefSetIt toIt)
+{
+ NodeListIt nodeFromIt = fromIt.value();
+ NodeListIt nodeToIt = toIt.value();
+
+ createAdjacency(&nodeFromIt->m_out, new AdjacencyNode(nodeToIt));
+ createAdjacency(&nodeToIt->m_in, new AdjacencyNode(nodeFromIt));
+}
+
+void DependencyGraph::deleteAdjacencies(AdjacencyNode *node)
+{
+ while (node) {
+ AdjacencyNode *next = node->m_next;
+ delete node;
+ node = next;
+ }
+}
+
+void DependencyGraph::createAdjacency(AdjacencyNode **node, AdjacencyNode *newNode)
+{
+ if (*node)
+ newNode->m_next = *node;
+ *node = newNode;
+}
diff --git a/src/plugins/clangcodemodel/dependencygraph.h b/src/plugins/clangcodemodel/dependencygraph.h
new file mode 100644
index 00000000000..9dccc37e04c
--- /dev/null
+++ b/src/plugins/clangcodemodel/dependencygraph.h
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef DEPENDENCYGRAPH_H
+#define DEPENDENCYGRAPH_H
+
+#include "includetracker.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ClangCodeModel {
+namespace Internal {
+
+class DependencyGraph : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(DependencyGraph)
+
+public:
+ DependencyGraph();
+ ~DependencyGraph();
+
+ void addFile(const QString &fileName, const QStringList &compilationOptions);
+
+ QFuture compute();
+
+ enum DependencyRole
+ {
+ FilesDirectlyIncludedBy, // Only direct inclusions
+ FilesIncludedBy, // Both direct and indirect inclusions
+ FilesWhichDirectlyInclude, // This one is directly included from...
+ FilesWhichInclude // This one is directly or indirectly included from...
+ };
+
+ /*
+ * You should use this version if you simply want all the dependencies, no matter what.
+ */
+ QStringList collectDependencies(const QString &referenceFile, DependencyRole role) const;
+
+ /*
+ * You should use this version if you might be interested on a particular dependency
+ * and don't want to continue the search once you have found it. In this case you need
+ * supply a visitor. Currently the visitor concept simply requires that a type Visitor_T
+ * models a function that will receive a file string s and indicate whether or not to
+ * continue:
+ *
+ * Visitor_T().acceptFile(s) must be a valid expression.
+ *
+ */
+ template
+ void collectDependencies(const QString &referenceFile,
+ DependencyRole role,
+ Visitor_T *visitor) const;
+
+ bool hasDependency(const QString &referenceFile, DependencyRole role) const;
+
+ void discard();
+
+signals:
+ void dependencyGraphAvailable();
+
+private:
+ QList > m_files;
+ IncludeTracker m_includeTracker;
+ QFutureWatcher m_computeWatcher;
+
+ void cancel();
+ void computeCore();
+
+ // The dependency graph is represent as an adjacency list. The vertices contains
+ // a list of *out* edges and a list of *in* edges. Each vertex corresponds to a file.
+ // Its out edges correspond to the files which get directly included by this one, while
+ // its in edges correspond to files that directly include this one.
+ //
+ // For better space efficiency, the adjacency nodes doen't explicitly store the file
+ // names themselves, but rather an iterator to the corresponding vertex. In addition,
+ // for speed efficiency we keep track of a hash table that contains iterators to the
+ // actual vertex storage container, which actually contains the strings for the file
+ // names. The vertex container itself is a linked list, it has the semantics we need,
+ // in particular regarding iterator invalidation.
+
+ struct AdjacencyNode;
+ struct Node
+ {
+ Node(const QString &fileName);
+
+ QString m_fileName;
+ AdjacencyNode *m_out;
+ AdjacencyNode *m_in;
+ };
+
+ typedef QLinkedList NodeList;
+ typedef NodeList::iterator NodeListIt;
+ typedef QHash NodeRefSet;
+ typedef NodeRefSet::iterator NodeRefSetIt;
+
+ struct AdjacencyNode
+ {
+ AdjacencyNode(NodeListIt it);
+
+ AdjacencyNode *m_next;
+ NodeListIt m_nodeIt;
+ };
+
+
+ void processIncludes(NodeRefSetIt currentFileIt,
+ const QStringList &compilationOptions);
+
+ template
+ void collectFilesBFS(NodeListIt nodeIt, DependencyRole role, Visitor_T *visitor) const;
+
+
+ // Core graph operations and data
+
+ QPair findVertex(const QString &s) const;
+ NodeRefSetIt insertVertex(const QString &s);
+ void insertEdge(NodeRefSetIt fromIt, NodeRefSetIt toIt);
+
+ void deleteAdjacencies(AdjacencyNode *node);
+ void createAdjacency(AdjacencyNode **node, AdjacencyNode *newNode);
+
+ NodeList m_nodes;
+ NodeRefSet m_nodesRefs;
+};
+
+template
+void DependencyGraph::collectDependencies(const QString &referenceFile,
+ DependencyRole role,
+ Visitor_T *visitor) const
+{
+ if (m_computeWatcher.isRunning())
+ return;
+
+ QPair v = findVertex(referenceFile);
+ if (!v.first)
+ return;
+
+ NodeListIt nodeIt = v.second.value();
+
+ if (role == FilesDirectlyIncludedBy || role == FilesWhichDirectlyInclude) {
+ AdjacencyNode *adj;
+ if (role == FilesDirectlyIncludedBy)
+ adj = nodeIt->m_out;
+ else
+ adj = nodeIt->m_in;
+
+ for (; adj; adj = adj->m_next) {
+ NodeListIt dependentIt = adj->m_nodeIt;
+ if (visitor->acceptFile(dependentIt->m_fileName))
+ return;
+ }
+ } else {
+ collectFilesBFS(nodeIt, role, visitor);
+ }
+}
+
+template
+void DependencyGraph::collectFilesBFS(NodeListIt nodeIt,
+ DependencyRole role,
+ Visitor_T *visitor) const
+{
+ Q_ASSERT(role == FilesIncludedBy || role == FilesWhichInclude);
+
+ if (m_computeWatcher.isRunning())
+ return;
+
+ QQueue q;
+ q.enqueue(nodeIt);
+
+ QSet visited;
+ visited.insert(nodeIt->m_fileName);
+
+ while (!q.isEmpty()) {
+ NodeListIt currentIt = q.dequeue();
+ AdjacencyNode *adj;
+ if (role == FilesIncludedBy)
+ adj = currentIt->m_out;
+ else
+ adj = currentIt->m_in;
+ while (adj) {
+ NodeListIt adjNodeIt = adj->m_nodeIt;
+ adj = adj->m_next;
+
+ const QString &adjFileName = adjNodeIt->m_fileName;
+ if (visited.contains(adjFileName))
+ continue;
+
+ if (visitor->acceptFile(adjFileName))
+ return;
+
+ visited.insert(adjFileName);
+ q.enqueue(adjNodeIt);
+ }
+ }
+}
+
+
+} // Internal
+} // ClangCodeModel
+
+#endif // DEPENDENCYGRAPH_H
diff --git a/src/plugins/clangcodemodel/diagnostic.cpp b/src/plugins/clangcodemodel/diagnostic.cpp
new file mode 100644
index 00000000000..f0aaef70fc3
--- /dev/null
+++ b/src/plugins/clangcodemodel/diagnostic.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "diagnostic.h"
+
+#include
+#include
+
+using namespace ClangCodeModel;
+
+Diagnostic::Diagnostic()
+ : m_severity(Unknown)
+ , m_length(0)
+{}
+
+Diagnostic::Diagnostic(Severity severity, const SourceLocation &location, unsigned length, const QString &spelling)
+ : m_severity(severity)
+ , m_loc(location)
+ , m_length(length)
+ , m_spelling(spelling)
+{}
+
+const QString Diagnostic::severityAsString() const
+{
+ if (m_severity == Unknown)
+ return QString();
+
+ static QStringList strs = QStringList()
+ << QCoreApplication::translate("Diagnostic", "ignored")
+ << QCoreApplication::translate("Diagnostic", "note")
+ << QCoreApplication::translate("Diagnostic", "warning")
+ << QCoreApplication::translate("Diagnostic", "error")
+ << QCoreApplication::translate("Diagnostic", "fatal")
+ ;
+
+ return strs.at(m_severity);
+}
diff --git a/src/plugins/clangcodemodel/diagnostic.h b/src/plugins/clangcodemodel/diagnostic.h
new file mode 100644
index 00000000000..8ecbcb09e7a
--- /dev/null
+++ b/src/plugins/clangcodemodel/diagnostic.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CLANG_DIAGNOSTIC_H
+#define CLANG_DIAGNOSTIC_H
+
+#include "clang_global.h"
+#include "sourcelocation.h"
+
+#include
+
+namespace ClangCodeModel {
+
+class CLANG_EXPORT Diagnostic
+{
+public:
+ enum Severity {
+ Unknown = -1,
+ Ignored = 0,
+ Note = 1,
+ Warning = 2,
+ Error = 3,
+ Fatal = 4
+ };
+
+public:
+ Diagnostic();
+ Diagnostic(Severity severity, const SourceLocation &location, unsigned length, const QString &spelling);
+
+ Severity severity() const
+ { return m_severity; }
+
+ const QString severityAsString() const;
+
+ const SourceLocation &location() const
+ { return m_loc; }
+
+ unsigned length() const
+ { return m_length; }
+
+ const QString &spelling() const
+ { return m_spelling; }
+
+private:
+ Severity m_severity;
+ SourceLocation m_loc;
+ unsigned m_length;
+ QString m_spelling;
+};
+
+} // namespace ClangCodeModel
+
+Q_DECLARE_METATYPE(ClangCodeModel::Diagnostic)
+Q_DECLARE_METATYPE(QList)
+
+#endif // CLANG_DIAGNOSTIC_H
diff --git a/src/plugins/clangcodemodel/fastindexer.cpp b/src/plugins/clangcodemodel/fastindexer.cpp
new file mode 100644
index 00000000000..bb122f3abc8
--- /dev/null
+++ b/src/plugins/clangcodemodel/fastindexer.cpp
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "fastindexer.h"
+
+using namespace ClangCodeModel::Internal;
+
+FastIndexer::~FastIndexer()
+{
+}
diff --git a/src/plugins/clangcodemodel/fastindexer.h b/src/plugins/clangcodemodel/fastindexer.h
new file mode 100644
index 00000000000..024d3d7b9ee
--- /dev/null
+++ b/src/plugins/clangcodemodel/fastindexer.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef FASTINDEXER_H
+#define FASTINDEXER_H
+
+#include "unit.h"
+
+namespace ClangCodeModel {
+namespace Internal {
+
+class FastIndexer
+{
+public:
+ virtual ~FastIndexer() = 0;
+
+ virtual void indexNow(const Unit &unit) = 0;
+};
+
+} // Internal namespace
+} // ClangCodeModel namespace
+
+#endif // FASTINDEXER_H
diff --git a/src/plugins/clangcodemodel/index.cpp b/src/plugins/clangcodemodel/index.cpp
new file mode 100644
index 00000000000..529ad48066b
--- /dev/null
+++ b/src/plugins/clangcodemodel/index.cpp
@@ -0,0 +1,491 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "clangsymbolsearcher.h"
+#include "index.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ClangCodeModel {
+namespace Internal {
+
+class ClangSymbolSearcher;
+
+class IndexPrivate
+{
+public:
+ IndexPrivate();
+
+ void insertSymbol(const Symbol &symbol, const QDateTime &timeStamp);
+ QList symbols(const QString &fileName) const;
+ QList