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();
    }

其中“名称”将是“重”、“测试”或“功能”。尽管在示例测试 c 文件中存在,但都没有找到它们。

我猜问题是索引没有重建,这导致 findBindings 返回一个空数组,即使我知道给定的变量名存在于 AST 中。

我当前启动索引器的尝试如下所示:

    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;
}

这基本上回答了问题的第二部分,因此我可以创建 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 回答