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()); }
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); }
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); }
// 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()); }
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; }
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); }
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); }
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; }
RemoveCastMethods(Document::Ptr doc, QTextDocument *document) : ASTVisitor(doc->translationUnit()), document(document) {}
FindASTNodes(Document::Ptr doc, QTextDocument *document) : ASTVisitor(doc->translationUnit()), document(document) { }
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; }