Exemplo n.º 1
0
void TestParseJob::testSimpleHtml()
{
    TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts;

    TestProject* project = new TestProject;
    m_projectController->closeAllProjects();
    m_projectController->addProject(project);

    TestFile f("<html><style>a { color: red; }</style></html>", "html", project);
    f.parse(features);

    ReferencedTopDUContext top = f.topContext();

    DUChainReadLocker lock;
    QVERIFY(top);
    QVERIFY(top->parsingEnvironmentFile()->language() == IndexedString("Css"));
    QCOMPARE(top->childContexts().count(), 1);
}
ReferencedTopDUContext ContextBuilder::buildContexts(Cpp::EnvironmentFilePointer file, AST *node, IncludeFileList* includes, const ReferencedTopDUContext& updateContext, bool removeOldImports)
{
  Q_ASSERT(file);
  setCompilingContexts(true);

  {
    DUChainWriteLocker lock(DUChain::lock());
    if(updateContext && (updateContext->parsingEnvironmentFile() && updateContext->parsingEnvironmentFile()->isProxyContext())) {
      kDebug(9007) << "updating a context " << file->url().str() << " from a proxy-context to a content-context";
      updateContext->parsingEnvironmentFile()->setIsProxyContext(false);
    }
  }

  if(editor()->currentUrl() != file->url())
    editor()->setCurrentUrl(file->url(), true);

  ReferencedTopDUContext topLevelContext;
  {
    DUChainWriteLocker lock(DUChain::lock());
    topLevelContext = updateContext;

    if( topLevelContext && topLevelContext->smartRange() && !(topLevelContext->parsingEnvironmentFile() && topLevelContext->parsingEnvironmentFile()->isProxyContext()))
      if (topLevelContext->smartRange()->parentRange()) { //Top-range must have no parent, else something is wrong with the structure
        kWarning() << *topLevelContext->smartRange() << "erroneously has a parent range" << *topLevelContext->smartRange()->parentRange();
        Q_ASSERT(false);
      }

    if (topLevelContext) {
      kDebug(9007) << "ContextBuilder::buildContexts: recompiling";
      setRecompiling(true);

      if (compilingContexts()) {
        // To here...
        LockedSmartInterface iface = editor()->smart();
        if (iface && topLevelContext->range().textRange() != iface.currentDocument()->documentRange()) {
          topLevelContext->setRange(SimpleRange(iface.currentDocument()->documentRange()));
          //This happens the whole file is deleted, and then a space inserted.
          kDebug(9007) << "WARNING: Top-level context has wrong size: " << topLevelContext->range().textRange() << " should be: " << iface.currentDocument()->documentRange();
        }
      }

      DUChain::self()->updateContextEnvironment( topLevelContext, const_cast<Cpp::EnvironmentFile*>(file.data() ) );
    } else {
      kDebug(9007) << "ContextBuilder::buildContexts: compiling";
      setRecompiling(false);

      Q_ASSERT(compilingContexts());

      LockedSmartInterface iface = editor()->smart();
      topLevelContext = new CppDUContext<TopDUContext>(editor()->currentUrl(), iface.currentDocument() ? SimpleRange(iface.currentDocument()->documentRange()) : SimpleRange(SimpleCursor(0,0), SimpleCursor(INT_MAX, INT_MAX)), const_cast<Cpp::EnvironmentFile*>(file.data()));

      topLevelContext->setSmartRange(editor()->topRange(iface, CppEditorIntegrator::DefinitionUseChain), DocumentRangeObject::Own);
      topLevelContext->setType(DUContext::Global);
      topLevelContext->setFlags((TopDUContext::Flags)(TopDUContext::UpdatingContext | topLevelContext->flags()));
      DUChain::self()->addDocumentChain(topLevelContext);
    
      topLevelContext->updateImportsCache(); //Mark that we will use a cached import-structure
    }

    setEncountered(topLevelContext);

    if (includes) {
      if(removeOldImports) {
        foreach (const DUContext::Import &parent, topLevelContext->importedParentContexts())
          if (!containsContext(*includes, dynamic_cast<TopDUContext*>(parent.context(0))))
            topLevelContext->removeImportedParentContext(parent.context(0));
      }

      QList< QPair<TopDUContext*, SimpleCursor> > realIncluded;
      QList< QPair<TopDUContext*, SimpleCursor> > realTemporaryIncluded;
      foreach (const LineContextPair &included, *includes)
        if(!included.temporary)
          realIncluded << qMakePair(included.context.data(), SimpleCursor(included.sourceLine, 0));
        else
          realTemporaryIncluded << qMakePair(included.context.data(), SimpleCursor(included.sourceLine, 0));

      topLevelContext->addImportedParentContexts(realIncluded);
      topLevelContext->addImportedParentContexts(realTemporaryIncluded, true);
      
      topLevelContext->updateImportsCache();
    }
  }

  {
    DUChainReadLocker lock(DUChain::lock());
    //If we're debugging the current file, dump its preprocessed contents and the AST
    ifDebugFile( HashedString(file->identity().url().str()), { kDebug() << stringFromContents(editor()->parseSession()->contentsVector()); Cpp::DumpChain dump; dump.dump(node, editor()->parseSession()); } );
Exemplo n.º 3
0
ReferencedTopDUContext ClangHelpers::buildDUChain(CXFile file, const Imports& imports, const ParseSession& session,
        TopDUContext::Features features, IncludeFileContexts& includedFiles,
        ClangIndex* index)
{
    if (includedFiles.contains(file)) {
        return {};
    }

    // prevent recursion
    includedFiles.insert(file, {});

    // ensure DUChain for imports are build properly
    foreach(const auto& import, imports.values(file)) {
        buildDUChain(import.file, imports, session, features, includedFiles, index);
    }

    const IndexedString path(QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath());
    if (path.isEmpty()) {
        // may happen when the file gets removed before the job is run
        return {};
    }

    const auto& environment = session.environment();

    bool update = false;
    UrlParseLock urlLock(path);
    ReferencedTopDUContext context;
    {
        DUChainWriteLocker lock;
        context = DUChain::self()->chainForDocument(path, &environment);
        if (!context) {
            context = ::createTopContext(path, environment);
        } else {
            update = true;
        }

        includedFiles.insert(file, context);
        if (update) {
            auto envFile = ClangParsingEnvironmentFile::Ptr(dynamic_cast<ClangParsingEnvironmentFile*>(context->parsingEnvironmentFile().data()));
            Q_ASSERT(envFile);
            if (!envFile->needsUpdate(&environment) && envFile->featuresSatisfied(features)) {
                return context;
            } else {
                //TODO: don't attempt to update if this environment is worse quality than the outdated one
                if (index && envFile->environmentQuality() < environment.quality()) {
                    index->pinTranslationUnitForUrl(environment.translationUnitUrl(), path);
                }
                envFile->setEnvironment(environment);
                envFile->setModificationRevision(ModificationRevision::revisionForFile(context->url()));
            }

            context->clearImportedParentContexts();
        }
        context->setFeatures(features);

        foreach(const auto& import, imports.values(file)) {
            Q_ASSERT(includedFiles.contains(import.file));
            auto ctx = includedFiles.value(import.file);
            if (!ctx) {
                // happens for cyclic imports
                continue;
            }
            context->addImportedParentContext(ctx, import.location);
        }
        context->updateImportsCache();
    }

    const auto problems = session.problemsForFile(file);
    {
        DUChainWriteLocker lock;
        context->setProblems(problems);
    }

    Builder::visit(session.unit(), file, includedFiles, update);

    return context;
}
Exemplo n.º 4
0
ReferencedTopDUContext ClangHelpers::buildDUChain(CXFile file, const Imports& imports, const ParseSession& session,
                                                  TopDUContext::Features features, IncludeFileContexts& includedFiles,
                                                  ClangIndex* index, const std::function<bool()>& abortFunction)
{
    if (includedFiles.contains(file)) {
        return {};
    }

    if (abortFunction && abortFunction()) {
        return {};
    }

    // prevent recursion
    includedFiles.insert(file, {});

    // ensure DUChain for imports are build properly
    foreach(const auto& import, imports.values(file)) {
        buildDUChain(import.file, imports, session, features, includedFiles, index, abortFunction);
    }

    const IndexedString path(QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath());
    if (path.isEmpty()) {
        // may happen when the file gets removed before the job is run
        return {};
    }

    const auto& environment = session.environment();

    bool update = false;
    UrlParseLock urlLock(path);
    ReferencedTopDUContext context;
    {
        DUChainWriteLocker lock;
        context = DUChain::self()->chainForDocument(path, &environment);
        if (!context) {
            context = ::createTopContext(path, environment);
        } else {
            update = true;
        }

        includedFiles.insert(file, context);
        if (update) {
            auto envFile = ClangParsingEnvironmentFile::Ptr(dynamic_cast<ClangParsingEnvironmentFile*>(context->parsingEnvironmentFile().data()));
            Q_ASSERT(envFile);
            if (!envFile)
                return context;

            /* NOTE: When we are here, then either the translation unit or one of its headers was changed.
             *       Thus we must always update the translation unit to propagate the change(s).
             *       See also: https://bugs.kde.org/show_bug.cgi?id=356327
             *       This assumes that headers are independent, we may need to improve that in the future
             *       and also update header files more often when other files included therein got updated.
             */
            if (path != environment.translationUnitUrl() && !envFile->needsUpdate(&environment) && envFile->featuresSatisfied(features)) {
                return context;
            } else {
                //TODO: don't attempt to update if this environment is worse quality than the outdated one
                if (index && envFile->environmentQuality() < environment.quality()) {
                    index->pinTranslationUnitForUrl(environment.translationUnitUrl(), path);
                }
                envFile->setEnvironment(environment);
                envFile->setModificationRevision(ModificationRevision::revisionForFile(context->url()));
            }

            context->clearImportedParentContexts();
        }
        context->setFeatures(features);

        foreach(const auto& import, imports.values(file)) {
            auto ctx = includedFiles.value(import.file);
            if (!ctx) {
                // happens for cyclic imports
                continue;
            }
            context->addImportedParentContext(ctx, import.location);
        }
        context->updateImportsCache();
    }

    const auto problems = session.problemsForFile(file);
    {
        DUChainWriteLocker lock;
        context->setProblems(problems);
    }

    Builder::visit(session.unit(), file, includedFiles, update);

    DUChain::self()->emitUpdateReady(path, context);

    return context;
}