1

私が取り組んでいるプログラムの一部では、プリプロセッサ マクロを名前で検索し、その値を取得する必要があります。CDT Indexer API を使用することにしました。正しい軌道に乗っていることを確認するために、単純な C ファイルを作成し、インデックスで特定のシンボルを検出できることを確認するだけのテスト メソッドを作成しました。ただし、そのテストを適切に実行できませんでした。IIndex.findBindings(char[], IndexFilter, IProgressMonitor) を使用しようとすると、AST に存在することがわかっているシンボルの空の配列が返されます。これは、テスト メソッドのサンプル ファイルの一部であるためです。

いくつかのカスタム クラスを使用しているため、正確なテスト メソッドを投稿することはできず、それらすべてを投稿するのはやり過ぎになるため、重要なコードのみを投稿します。まず、サンプル ファイル:

    final String exampleCode =
        "#define HEAVY 20\n" +
        "#define TEST 5\n" +
        "void function() { }\n" +
        "int main() { return 0; }\n";
    IFile exampleFile = testProject.getFile("findCodeFromIndex.c");
    exampleFile.create(new ByteArrayInputStream(exampleCode.getBytes("UTF-8") ), true, null);

そのファイルから IASTTranslationUnit を自動的に取得するカスタム クラスがあります。翻訳単位は問題ありません (マクロを除くすべてを構成するノードを確認できます)。その AST からインデックスを取得し、インデックスを検索するために使用するコードは次のとおりです。

    try {
        index.acquireReadLock();
        returnBinding = index.findBindings(name.toCharArray(), IndexFilter.ALL, null);

    ... catch stuff... 
    } finally {
        index.releaseReadLock();
    }

「name」は、「HEAVY」、「TEST」、または「function」のいずれかになります。サンプルのテスト c ファイルに存在するにもかかわらず、それらのいずれも見つかりません。

問題は、インデックスが再構築されていないことであると推測しています。これにより、指定された変数名が AST に存在することがわかっていても、findBindings は空の配列を返します。

インデクサーを起動しようとする現在の試みは次のようになります。

    final ICProject cProject = CoreModel.getDefault().getCModel().getCProject(testProject.getName());
    CCorePlugin.getIndexManager().reindex(cProject);
    CCorePlugin.getIndexManager().joinIndexer(IIndexManager.FOREVER, new NullProgressMonitor() );

質問の内訳:

1) インデックスの検索方法は適切ですか?

2) 問題がインデックスを再構築する必要がある場合、テスト メソッドに対してインデックスを最新の状態にするにはどうすればよいですか? それ以外の場合、存在することがわかっているマクロ/関数のバインディングを解決しない理由は何ですか?

4

1 に答える 1

3

私は自分の問題を解決したので、ここに投稿します。プロジェクトが適切な C プロジェクトではないことがインデクサーの適切な動作を妨げているという私のコメントは正しかったのですが、必要なマクロを取得するには、インデクサーで別の方法を使用する必要があることもわかりました。

テスト環境のセットアップ:

これは、基本的な C プロジェクトを作成するコードです。これが果たす唯一の目的は、インデクサーがテスト メソッドに対して機能できるようにすることです。それでも、それは大きいです:

public static IProject createBareCProject(String name) throws Exception {
    IProject bareProjectHandle = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
    IProjectDescription description =
        bareProjectHandle.getWorkspace().newProjectDescription("TestProject");

    description.setLocationURI(bareProjectHandle.getLocationURI() );

    IProject bareProject =
        CCorePlugin.getDefault().createCDTProject(description, bareProjectHandle, new NullProgressMonitor() );

    IManagedBuildInfo buildInfo = ManagedBuildManager.createBuildInfo(bareProject);
    IManagedProject projectManaged =
        ManagedBuildManager
            .createManagedProject(bareProject, 
                                  ManagedBuildManager.getExtensionProjectType("cdt.managedbuild.target.gnu.mingw.exe") );

    List<IConfiguration> configs = getValidConfigsForPlatform();
    IConfiguration config = 
        projectManaged.createConfiguration(
                configs.get(0), 
                ManagedBuildManager.calculateChildId(configs.get(0).getId(), null));

    ICProjectDescription cDescription = 
        CoreModel.getDefault().getProjectDescriptionManager().createProjectDescription(bareProject, false);

    ICConfigurationDescription cConfigDescription = 
        cDescription.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, config.getConfigurationData() );

    cDescription.setActiveConfiguration(cConfigDescription);
    cConfigDescription.setSourceEntries(null);
    IFolder srcFolder = bareProject.getFolder("src");
    srcFolder.create(true, true, null);
    ICSourceEntry srcFolderEntry = new CSourceEntry(srcFolder, null, ICSettingEntry.RESOLVED);
    cConfigDescription.setSourceEntries(new ICSourceEntry[] { srcFolderEntry });

    buildInfo.setManagedProject(projectManaged);

    cDescription.setCdtProjectCreated();

    IIndexManager indexMgr = CCorePlugin.getIndexManager();
    ICProject cProject = CoreModel.getDefault().getCModel().getCProject(bareProject.getName() );
    indexMgr.setIndexerId(cProject, IPDOMManager.ID_FAST_INDEXER);

    CoreModel.getDefault().setProjectDescription(bareProject, cDescription);

    ManagedBuildManager.setDefaultConfiguration(bareProject, config );
    ManagedBuildManager.setSelectedConfiguration(bareProject, config );

    ManagedBuildManager.setNewProjectVersion(bareProject);

    ManagedBuildManager.saveBuildInfo(bareProject, true);

    return bareProject;

}

デバッグ中に発見したように、プロジェクトにこれらの機能が設定されていない限り、インデクサーは延期されたため、適切な構成と説明を設定することが実際に重要です。初期構成の開始点としてプラットフォームの構成を取得するには:

public static List<IConfiguration> getValidConfigsForPlatform() {
    List<IConfiguration> configurations = 
        new ArrayList<IConfiguration>();

    for (IConfiguration cfg : ManagedBuildManager.getExtensionConfigurations() ) {
        IToolChain currentToolChain =
            cfg.getToolChain();

        if ( (currentToolChain != null )                           && 
             (ManagedBuildManager.isPlatformOk(currentToolChain) ) &&
             (currentToolChain.isSupported() )                     ) {

            configurations.add(cfg);
        }
    }
    return configurations;
}

これは基本的に質問の 2 番目の部分に答えているため、インデックスを使用してコードをテストする目的で ac プロジェクトを作成できます。テスト コードはまだいくつかの作業を行う必要があります。

コードのテスト

プロジェクトの "src" フォルダー (上記のコードで作成) にファイルを作成し、それらに .c という名前を付けるか、.h という名前を付けたい場合は、それらを .c ファイルに含める必要があります (そうでない場合)。インデクサーはそれらを認識しません)。最後に、ファイルにテスト コードを入力します。1番に答えるには、

Eclipse の自動更新ジョブとインデックスの両方をブロックする必要があります。

public static void forceIndexUpdate(IProject project) throws Exception {
    ICProject cProject = CoreModel.getDefault().create(project);
    Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_REFRESH, null);
    CCorePlugin.getIndexManager().reindex(cProject);
    CCorePlugin.getIndexManager().joinIndexer(IIndexManager.FOREVER, new NullProgressMonitor() );
    assertTrue(CCorePlugin.getIndexManager().isIndexerIdle() );
    assertFalse(CCorePlugin.getIndexManager().isIndexerSetupPostponed(cProject));
}

プロジェクト内のファイルを変更した後。これにより、Eclipse が確実に更新され、インデクサーが延期されることなく完了するようになります。最後に、インデクサーに応じてテストを実行できます。

そして最後のポイントは、IBinding の使い方を間違っていたことです。マクロを取得できた正しい方法は、メソッドを使用することでしたIIndex.findMacros(char[] name, IndexFilter filter, IProgressMonitor monitor)

これが少なくとも誰かに役立つことを願っています。また、このソリューションの有効性に関するフィードバックがあれば幸いです。これは、私が作成して機能した最初のソリューションであるためです。念のために言っておきますが、私はインデクサー自体をテストしているのではなく、インデクサーを使用するコードを書いたので、その重要性を考慮してできるだけ現実的な条件下でテストしたいと考えています。

于 2013-07-24T16:00:47.220 に答える