QString DoxygenGenerator::generate(QTextCursor cursor)
{
    const QChar &c = cursor.document()->characterAt(cursor.position());
    if (!c.isLetter() && c != QLatin1Char('_'))
        return QString();

    // Try to find what would be the declaration we are interested in.
    SimpleLexer lexer;
    QTextBlock block = cursor.block();
    while (block.isValid()) {
        const QString &text = block.text();
        const QList<Token> &tks = lexer(text);
        foreach (const Token &tk, tks) {
            if (tk.is(T_SEMICOLON) || tk.is(T_LBRACE)) {
                // No need to continue beyond this, we might already have something meaningful.
                cursor.setPosition(block.position() + tk.end(), QTextCursor::KeepAnchor);
                break;
            }
        }

        if (cursor.hasSelection())
            break;

        block = block.next();
    }

    if (!cursor.hasSelection())
        return QString();

    QString declCandidate = cursor.selectedText();
    declCandidate.replace(QChar::ParagraphSeparator, QLatin1Char('\n'));

    // Let's append a closing brace in the case we got content like 'class MyType {'
    if (declCandidate.endsWith(QLatin1Char('{')))
        declCandidate.append(QLatin1Char('}'));

    Document::Ptr doc = Document::create(QLatin1String("<doxygen>"));
    doc->setUtf8Source(declCandidate.toUtf8());
    doc->parse(Document::ParseDeclaration);
    doc->check(Document::FastCheck);

    if (!doc->translationUnit()
            || !doc->translationUnit()->ast()
            || !doc->translationUnit()->ast()->asDeclaration()) {
        return QString();
    }

    return generate(cursor, doc->translationUnit()->ast()->asDeclaration());
}
예제 #2
0
void tst_Misc::findBreakpoints3()
{
    const QByteArray src("\n"                       // line 0
                         "int foo() {\n"
                         "  try {\n"                // line 2
                         "    bar();\n"             // line 3
                         "  } catch (Mooze &m) {\n" // line 4
                         "    wooze();\n"           // line 5
                         "  }\n"
                         "  return 0;\n"            // line 7
                         "}\n"
                         );
    Document::Ptr doc = Document::create("findCatchBreakpoint");
    QVERIFY(!doc.isNull());
    doc->setUtf8Source(src);
    bool success = doc->parse();
    QVERIFY(success);
    QCOMPARE(doc->diagnosticMessages().size(), 0);
    FindCdbBreakpoint findBreakpoint(doc->translationUnit());

    QCOMPARE(findBreakpoint(2), 3U);
    QCOMPARE(findBreakpoint(3), 3U);
    QCOMPARE(findBreakpoint(4), 5U);
    QCOMPARE(findBreakpoint(5), 5U);
    QCOMPARE(findBreakpoint(7), 7U);
}
예제 #3
0
void tst_Misc::findBreakpoints2()
{
    const QByteArray src("\n"                   // line 0
                         "void foo() {\n"
                         "  int a = 2;\n"       // line 2
                         "  switch (x) {\n"     // line 3
                         "  case 1: {\n"        // line 4
                         "      int y = 2;\n"   // line 5
                         "      y++;\n"
                         "      break;\n"       // line 7
                         "  }\n"
                         "  }\n"
                         "}\n"
                         );
    Document::Ptr doc = Document::create("findSwitchBreakpoint");
    QVERIFY(!doc.isNull());
    doc->setUtf8Source(src);
    bool success = doc->parse();
    QVERIFY(success);
    QCOMPARE(doc->diagnosticMessages().size(), 0);
    FindCdbBreakpoint findBreakpoint(doc->translationUnit());

    QCOMPARE(findBreakpoint(0), 2U);
    QCOMPARE(findBreakpoint(1), 2U);
    QCOMPARE(findBreakpoint(2), 2U);
    QCOMPARE(findBreakpoint(3), 3U);
    QCOMPARE(findBreakpoint(4), 5U);
    QCOMPARE(findBreakpoint(5), 5U);
    QCOMPARE(findBreakpoint(6), 6U);
    QCOMPARE(findBreakpoint(7), 7U);
}
예제 #4
0
// Resolves auto and decltype initializer string
QList<LookupItem> TypeResolver::resolveDeclInitializer(
        CreateBindings &factory, const Declaration *decl,
        const QSet<const Declaration* > &declarationsBeingResolved,
        const Identifier *id)
{
    const StringLiteral *initializationString = decl->getInitializer();
    if (initializationString == 0)
        return QList<LookupItem>();

    const QByteArray &initializer =
            QByteArray::fromRawData(initializationString->chars(),
                                    initializationString->size()).trimmed();

    // Skip lambda-function initializers
    if (initializer.length() > 0 && initializer[0] == '[')
        return QList<LookupItem>();

    TypeOfExpression exprTyper;
    exprTyper.setExpandTemplates(true);
    Document::Ptr doc = factory.snapshot().document(QString::fromLocal8Bit(decl->fileName()));
    exprTyper.init(doc, factory.snapshot(), factory.sharedFromThis(), declarationsBeingResolved);

    Document::Ptr exprDoc =
            documentForExpression(exprTyper.preprocessedExpression(initializer));
    factory.addExpressionDocument(exprDoc);
    exprDoc->check();

    if (id) {
        DeduceAutoCheck deduceAuto(id, exprDoc->translationUnit());
        if (deduceAuto._block)
            return QList<LookupItem>();
    }

    return exprTyper(extractExpressionAST(exprDoc), exprDoc, decl->enclosingScope());
}
예제 #5
0
        static Document::Ptr create(const QByteArray &source)
        {
            LanguageFeatures features;
            features.objCEnabled = true;
            features.qtEnabled = false;
            features.qtKeywordsEnabled = false;
            features.qtMocRunEnabled = false;

            Document::Ptr document = Document::Ptr(new Document);
            document->translationUnit()->setLanguageFeatures(features);
            const QByteArray preprocessedSource = preprocess(source);
            document->translationUnit()->setSource(preprocessedSource.constData(),
                                                preprocessedSource.length());
            document->translationUnit()->parse();

            if (document->hasParsingErrors())
                return Document::Ptr();
            return document;
        }
예제 #6
0
void tst_Misc::findBreakpoints()
{
    const QByteArray src("\n"                   // line 0
                         "class C {\n"
                         "  int a;\n"
                         "  C():\n"
                         "    a(0)\n"           // line 4
                         "  {\n"                // line 5
                         "  }\n"
                         "  void empty()\n"     // line 7
                         "  {\n"                // line 8
                         "  }\n"
                         "  void misc()    \n"
                         "  {              \n"  // line 11
                         "    if (         \n"  // line 12
                         "          a      \n"  // line 13
                         "        &&       \n"  // line 14
                         "          b      \n"  // line 15
                         "       )         \n"  // line 16
                         "    {            \n"  // line 17
                         "    }            \n"  // line 18
                         "    while (      \n"  // line 19
                         "          a      \n"  // line 20
                         "        &&       \n"  // line 21
                         "          b      \n"  // line 22
                         "       )         \n"  // line 23
                         "    {            \n"  // line 24
                         "    }            \n"  // line 25
                         "    do {         \n"  // line 26
                         "    }            \n"  // line 27
                         "    while (      \n"  // line 28
                         "          a      \n"  // line 39
                         "        &&       \n"  // line 30
                         "          b      \n"  // line 31
                         "       );        \n"  // line 32
                         "  }              \n"
                         "};               \n"
                         );
    Document::Ptr doc = Document::create("findContstructorBreakpoint");
    QVERIFY(!doc.isNull());
    doc->setUtf8Source(src);
    bool success = doc->parse();
    QVERIFY(success);
    QCOMPARE(doc->diagnosticMessages().size(), 0);
    FindCdbBreakpoint findBreakpoint(doc->translationUnit());

    QCOMPARE(findBreakpoint(0), 5U);
    QCOMPARE(findBreakpoint(7), 8U);
    QCOMPARE(findBreakpoint(11), 16U);
    QCOMPARE(findBreakpoint(17), 23U);
    QCOMPARE(findBreakpoint(18), 23U);
}
예제 #7
0
void tst_Lookup::base_class_defined_1()
{
    Overview overview;

    const QByteArray source = "\n"
        "class base {};\n"
        "class derived: public base {};\n";

    Document::Ptr doc = Document::create("base_class_defined_1");
    doc->setSource(source);
    doc->parse();
    doc->check();

    QVERIFY(doc->diagnosticMessages().isEmpty());
    QCOMPARE(doc->globalSymbolCount(), 2U);

    Snapshot snapshot;
    snapshot.insert(doc->fileName(), doc);

    Document::Ptr emptyDoc = Document::create("<empty>");

    Class *baseClass = doc->globalSymbolAt(0)->asClass();
    QVERIFY(baseClass);

    Class *derivedClass = doc->globalSymbolAt(1)->asClass();
    QVERIFY(derivedClass);

    LookupContext ctx(derivedClass, emptyDoc, doc, snapshot);

    const QList<Symbol *> candidates =
        ctx.resolveClass(derivedClass->baseClassAt(0)->name());

    QCOMPARE(candidates.size(), 1);
    QCOMPARE(candidates.at(0), baseClass);

    TranslationUnit *unit = doc->translationUnit();
    QVERIFY(unit != 0);

    TranslationUnitAST *ast = unit->ast()->asTranslationUnit();
    QVERIFY(ast != 0);

    ClassSymbols classSymbols(doc->control());
    classSymbols(ast);

    QCOMPARE(classSymbols.size(), 2);

    const QMap<Class *, ClassSpecifierAST *> classToAST =
            invert(classSymbols.asMap());

    QVERIFY(classToAST.value(baseClass) != 0);
    QVERIFY(classToAST.value(derivedClass) != 0);
}
예제 #8
0
void tst_Lookup::base_class_defined_1()
{
    Overview overview;

    const QByteArray source = "\n"
        "class base {};\n"
        "class derived: public base {};\n";

    Document::Ptr doc = Document::create("base_class_defined_1");
    doc->setUtf8Source(source);
    doc->parse();
    doc->check();

    QVERIFY(doc->diagnosticMessages().isEmpty());
    QCOMPARE(doc->globalSymbolCount(), 2U);

    Snapshot snapshot;
    snapshot.insert(doc);

    Class *baseClass = doc->globalSymbolAt(0)->asClass();
    QVERIFY(baseClass);

    Class *derivedClass = doc->globalSymbolAt(1)->asClass();
    QVERIFY(derivedClass);

    const LookupContext ctx(doc, snapshot);

    LookupScope *klass = ctx.lookupType(derivedClass->baseClassAt(0)->name(), derivedClass->enclosingScope());
    QVERIFY(klass != 0);

    QCOMPARE(klass->symbols().size(), 1);
    QCOMPARE(klass->symbols().first(), baseClass);

    TranslationUnit *unit = doc->translationUnit();
    QVERIFY(unit != 0);

    TranslationUnitAST *ast = unit->ast()->asTranslationUnit();
    QVERIFY(ast != 0);

    ClassSymbols classSymbols(unit);
    classSymbols(ast);

    QCOMPARE(classSymbols.size(), 2);

    const QMap<Class *, ClassSpecifierAST *> classToAST =
            invert(classSymbols.asMap());

    QVERIFY(classToAST.value(baseClass) != 0);
    QVERIFY(classToAST.value(derivedClass) != 0);
}
/// Currently, we return the end of fileName.cpp
/// \todo take the definitions of the surrounding declarations into account
QList<InsertionLocation> InsertionPointLocator::methodDefinition(
    Declaration *declaration) const
{
    QList<InsertionLocation> result;
    if (!declaration)
        return result;

    const QString declFileName = QString::fromUtf8(declaration->fileName(),
                                                   declaration->fileNameLength());
    QString target = declFileName;
    if (!isSourceFile(declFileName)) {
        Internal::CppToolsPlugin *cpptools = Internal::CppToolsPlugin::instance();
        QString candidate = cpptools->correspondingHeaderOrSource(declFileName);
        if (!candidate.isEmpty())
            target = candidate;
    }

    Document::Ptr doc = m_refactoringChanges->file(target).cppDocument();
    if (doc.isNull())
        return result;

    Snapshot simplified = m_refactoringChanges->snapshot().simplified(doc);
    if (Symbol *s = simplified.findMatchingDefinition(declaration)) {
        if (Function *f = s->asFunction()) {
            if (f->isConst() == declaration->type().isConst()
                    && f->isVolatile() == declaration->type().isVolatile())
                return result;
        }
    }

    TranslationUnit *xUnit = doc->translationUnit();
    unsigned tokenCount = xUnit->tokenCount();
    if (tokenCount < 2) // no tokens available
        return result;

    unsigned line = 0, column = 0;
    xUnit->getTokenEndPosition(xUnit->tokenCount() - 2, &line, &column);

    const QLatin1String prefix("\n\n");
    result.append(InsertionLocation(target, prefix, QString(), line, column));

    return result;
}
예제 #10
0
 RemoveCastMethods(Document::Ptr doc, QTextDocument *document)
     : ASTVisitor(doc->translationUnit()), document(document) {}
예제 #11
0
 FindASTNodes(Document::Ptr doc, QTextDocument *document)
     : ASTVisitor(doc->translationUnit()), document(document)
 {
 }
예제 #12
0
Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffset)
{
    Utils::ChangeSet changes;

    // parse the current source declaration
    TypeOfExpression typeOfExpression; // ### just need to preprocess...
    typeOfExpression.init(sourceDocument, snapshot);

    QString newDeclText = linkSelection.selectedText();
    for (int i = 0; i < newDeclText.size(); ++i) {
        if (newDeclText.at(i).toAscii() == 0)
            newDeclText[i] = QLatin1Char('\n');
    }
    newDeclText.append(QLatin1String("{}"));
    const QString newDeclTextPreprocessed = typeOfExpression.preprocess(newDeclText);

    Document::Ptr newDeclDoc = Document::create(QLatin1String("<decl>"));
    newDeclDoc->setSource(newDeclTextPreprocessed.toUtf8());
    newDeclDoc->parse(Document::ParseDeclaration);
    newDeclDoc->check();

    // extract the function symbol
    if (!newDeclDoc->translationUnit()->ast())
        return changes;
    FunctionDefinitionAST *newDef = newDeclDoc->translationUnit()->ast()->asFunctionDefinition();
    if (!newDef)
        return changes;
    Function *newFunction = newDef->symbol;
    if (!newFunction)
        return changes;

    Overview overview;
    overview.setShowReturnTypes(true);
    overview.setShowTemplateParameters(true);
    overview.setShowArgumentNames(true);
    overview.setShowFunctionSignatures(true);

    // abort if the name of the newly parsed function is not the expected one
    DeclaratorIdAST *newDeclId = getDeclaratorId(newDef->declarator);
    if (!newDeclId || !newDeclId->name || !newDeclId->name->name
            || overview(newDeclId->name->name) != nameInitial) {
        return changes;
    }

    LookupContext sourceContext(sourceDocument, snapshot);
    LookupContext targetContext(targetFile->cppDocument(), snapshot);

    // sync return type
    {
        // set up for rewriting return type
        SubstitutionEnvironment env;
        env.setContext(sourceContext);
        env.switchScope(sourceFunction->enclosingScope());
        ClassOrNamespace *targetCoN = targetContext.lookupType(targetFunction->enclosingScope());
        if (!targetCoN)
            targetCoN = targetContext.globalNamespace();
        UseMinimalNames q(targetCoN);
        env.enter(&q);
        Control *control = sourceContext.control().data();

        // get return type start position and declarator info from declaration
        DeclaratorAST *declarator = 0;
        SpecifierAST *firstReplaceableSpecifier = 0;
        TranslationUnit *targetTranslationUnit = targetFile->cppDocument()->translationUnit();
        if (SimpleDeclarationAST *simple = targetDeclaration->asSimpleDeclaration()) {
            declarator = simple->declarator_list->value;
            firstReplaceableSpecifier = findFirstReplaceableSpecifier(
                        targetTranslationUnit, simple->decl_specifier_list);
        } else if (FunctionDefinitionAST *def = targetDeclaration->asFunctionDefinition()) {
            declarator = def->declarator;
            firstReplaceableSpecifier = findFirstReplaceableSpecifier(
                        targetTranslationUnit, def->decl_specifier_list);
        }

        int returnTypeStart = 0;
        if (firstReplaceableSpecifier)
            returnTypeStart = targetFile->startOf(firstReplaceableSpecifier);
        else
            returnTypeStart = targetFile->startOf(declarator);

        if (!newFunction->returnType().isEqualTo(sourceFunction->returnType())
                && !newFunction->returnType().isEqualTo(targetFunction->returnType())) {
            FullySpecifiedType type = rewriteType(newFunction->returnType(), &env, control);
            const QString replacement = overview(type, targetFunction->name());
            changes.replace(returnTypeStart,
                            targetFile->startOf(targetFunctionDeclarator->lparen_token),
                            replacement);
        }
    }

    // sync parameters
    {
        // set up for rewriting parameter types
        SubstitutionEnvironment env;
        env.setContext(sourceContext);
        env.switchScope(sourceFunction);
        ClassOrNamespace *targetCoN = targetContext.lookupType(targetFunction);
        if (!targetCoN)
            targetCoN = targetContext.globalNamespace();
        UseMinimalNames q(targetCoN);
        env.enter(&q);
        Control *control = sourceContext.control().data();
        Overview overview;

        const unsigned sourceArgCount = declaredArgumentCount(sourceFunction);
        const unsigned newArgCount = declaredArgumentCount(newFunction);
        const unsigned targetArgCount = declaredArgumentCount(targetFunction);

        // check if parameter types or names have changed
        const unsigned existingArgs = qMin(targetArgCount, newArgCount);
        ParameterDeclarationClauseAST *targetParameterDecl =
                targetFunctionDeclarator->parameter_declaration_clause;
        ParameterDeclarationListAST *firstTargetParameterDeclIt =
                targetParameterDecl ? targetParameterDecl->parameter_declaration_list : 0;
        ParameterDeclarationListAST *targetParameterDeclIt = firstTargetParameterDeclIt;
        for (unsigned i = 0;
             i < existingArgs && targetParameterDeclIt;
             ++i, targetParameterDeclIt = targetParameterDeclIt->next) {
            Symbol *targetParam = targetFunction->argumentAt(i);
            Symbol *newParam = newFunction->argumentAt(i);

            // if new's name and type are the same as source's, forbid changes
            bool allowChangeType = true;
            const Name *replacementName = newParam->name();
            if (i < sourceArgCount) {
                Symbol *sourceParam = sourceFunction->argumentAt(i);
                if (newParam->type().isEqualTo(sourceParam->type()))
                    allowChangeType = false;
                if (namesEqual(replacementName, sourceParam->name()))
                    replacementName = targetParam->name();
            }

            // don't change the name if it's in a comment
            if (hasCommentedName(targetFile->cppDocument()->translationUnit(),
                                 targetFile->cppDocument()->source(),
                                 targetFunctionDeclarator, i))
                replacementName = 0;

            // find the end of the parameter declaration
            ParameterDeclarationAST *targetParamAst = targetParameterDeclIt->value;
            int parameterNameEnd = 0;
            if (targetParamAst->declarator)
                parameterNameEnd = targetFile->endOf(targetParamAst->declarator);
            else if (targetParamAst->type_specifier_list)
                parameterNameEnd = targetFile->endOf(targetParamAst->type_specifier_list->lastToken() - 1);
            else
                parameterNameEnd = targetFile->startOf(targetParamAst);

            // change name and type?
            if (allowChangeType
                    && !targetParam->type().isEqualTo(newParam->type())) {
                FullySpecifiedType replacementType = rewriteType(newParam->type(), &env, control);
                const QString replacement = overview(replacementType, replacementName);

                changes.replace(targetFile->startOf(targetParamAst),
                                parameterNameEnd,
                                replacement);
            }
            // change the name only?
            else if (!namesEqual(targetParam->name(), replacementName)) {
                DeclaratorIdAST *id = getDeclaratorId(targetParamAst->declarator);
                QString replacementNameStr = overview(replacementName);
                if (id) {
                    changes.replace(targetFile->range(id), replacementNameStr);
                } else {
                    // add name to unnamed parameter
                    replacementNameStr.prepend(QLatin1Char(' '));
                    int end;
                    if (targetParamAst->equal_token) {
                        end = targetFile->startOf(targetParamAst->equal_token);
                        replacementNameStr.append(QLatin1Char(' '));
                    } else {
                        // one past end on purpose
                        end = targetFile->startOf(targetParamAst->lastToken());
                    }
                    changes.replace(parameterNameEnd, end, replacementNameStr);
                }
            }
        }
        // remove some parameters?
        if (newArgCount < targetArgCount) {
            targetParameterDeclIt = firstTargetParameterDeclIt;
            if (targetParameterDeclIt) {
                if (newArgCount == 0) {
                    changes.remove(targetFile->startOf(targetParameterDeclIt->firstToken()),
                                   targetFile->endOf(targetParameterDeclIt->lastToken() - 1));
                } else {
                    // get the last valid argument
                    for (unsigned i = 0; i < newArgCount - 1 && targetParameterDeclIt; ++i)
                        targetParameterDeclIt = targetParameterDeclIt->next;
                    if (targetParameterDeclIt) {
                        const int start = targetFile->endOf(targetParameterDeclIt->value);
                        const int end = targetFile->endOf(targetParameterDecl->lastToken() - 1);
                        changes.remove(start, end);
                    }
                }
            }
        }
        // add some parameters?
        else if (newArgCount > targetArgCount) {
            QString newParams;
            for (unsigned i = targetArgCount; i < newArgCount; ++i) {
                Symbol *param = newFunction->argumentAt(i);
                FullySpecifiedType type = rewriteType(param->type(), &env, control);
                if (i != 0)
                    newParams += QLatin1String(", ");
                newParams += overview(type, param->name());
            }
            targetParameterDeclIt = firstTargetParameterDeclIt;
            if (targetParameterDeclIt) {
                while (targetParameterDeclIt->next)
                    targetParameterDeclIt = targetParameterDeclIt->next;
                changes.insert(targetFile->endOf(targetParameterDeclIt->value), newParams);
            } else {
                changes.insert(targetFile->endOf(targetFunctionDeclarator->lparen_token), newParams);
            }
        }
    }

    // sync cv qualification
    if (targetFunction->isConst() != newFunction->isConst()
            || targetFunction->isVolatile() != newFunction->isVolatile()) {
        QString cvString;
        if (newFunction->isConst())
            cvString += QLatin1String("const");
        if (newFunction->isVolatile()) {
            if (!cvString.isEmpty())
                cvString += QLatin1Char(' ');
            cvString += QLatin1String("volatile");
        }
        const int rparenEnd = targetFile->endOf(targetFunctionDeclarator->rparen_token);
        if (targetFunctionDeclarator->cv_qualifier_list) {
            const int cvEnd = targetFile->endOf(targetFunctionDeclarator->cv_qualifier_list->lastToken() - 1);
            // if the qualifies changed, replace
            if (!cvString.isEmpty()) {
                changes.replace(targetFile->startOf(targetFunctionDeclarator->cv_qualifier_list->firstToken()),
                                cvEnd, cvString);
            } else {
                // remove
                changes.remove(rparenEnd, cvEnd);
            }
        } else {
            // otherwise add
            cvString.prepend(QLatin1Char(' '));
            changes.insert(rparenEnd, cvString);
        }
    }

    if (targetOffset != -1) {
        // move all change operations to have the right start offset
        const int moveAmount = targetOffset - targetFile->startOf(targetDeclaration);
        QList<Utils::ChangeSet::EditOp> ops = changes.operationList();
        for (int i = 0; i < ops.size(); ++i) {
            ops[i].pos1 += moveAmount;
            ops[i].pos2 += moveAmount;
        }
        changes = Utils::ChangeSet(ops);
    }

    return changes;
}