we can have a look at this function in editormanager.cpp
bool EditorManager::SwapActiveHeaderSource()
{
    cbEditor* ed = GetBuiltinEditor(GetActiveEditor());
    if (!ed)
        return false;
    FileType ft = FileTypeOf(ed->GetFilename());
    if (ft != ftHeader && ft != ftSource)
        return false;
    // because ft == ftHeader || ftSource, the extension has at least 1 character
    bool extStartsWithCapital = wxIsupper(wxFileName(ed->GetFilename()).GetExt()[0]);
    // create a list of search dirs
    wxArrayString dirs;
    cbProject* project = 0;
    // if the file in question belongs to a different open project,
    // then use that project instead.
    // this fixes locating the file's pair in a workspace when the active file
    // does not belong to the active project.
    ProjectFile* opf = ed->GetProjectFile();
    if (opf)
        project = opf->GetParentProject();
    // if we didn't get a valid project, try the active one
    if (!project)
        project = Manager::Get()->GetProjectManager()->GetActiveProject();
    if (project)
    {
        // get project's include dirs
        dirs = project->GetIncludeDirs();
        if (opf)
        {
            wxString const &activeName = opf->file.GetName();
            // first try to find the file among the opened files
            for (int i = 0; i < GetEditorsCount(); ++i)
            {
                cbEditor* edit = GetBuiltinEditor(GetEditor(i));
                if (!edit)
                    continue;
                ProjectFile* pf = edit->GetProjectFile();
                if (!pf)
                    continue;
                if (pf->file.GetName() == activeName)
                {
                    wxFileName const & fname = pf->file;
                    FileType ft_other = FileTypeOf(fname.GetFullName());
                    if (   (    ((ft == ftHeader) && (ft_other == ftSource))
                             || ((ft == ftSource) && (ft_other == ftHeader)) )
                        && (wxIsupper(fname.GetExt()[0]) == extStartsWithCapital) )
                    {
                        if (fname.FileExists())
                        {
                            cbEditor* newEd = Open(fname.GetFullPath());
                            if (newEd!=0L) // we found and were able to open it
                                return true; // --> RETURN
                        }
                    }
                }
            }
            // second try to find in the project files - at the same time
            // build the directory list for further searching if not
            // successful now
            for (int i = 0; i < project->GetFilesCount(); ++i)
            {
                ProjectFile* pf = project->GetFile(i);
                if (!pf)
                    continue;
                wxString dir = pf->file.GetPath(wxPATH_GET_VOLUME);
                if (dirs.Index(dir) == wxNOT_FOUND)
                    dirs.Add(dir);
                if (pf->file.GetName() == activeName)
                {
                    wxFileName const & fname = pf->file;
                    FileType ft_other = FileTypeOf(fname.GetFullName());
                    if (   (    ((ft == ftHeader) && (ft_other == ftSource))
                             || ((ft == ftSource) && (ft_other == ftHeader)) )
                        && (wxIsupper(fname.GetExt()[0]) == extStartsWithCapital) )
                    {
                        if (fname.FileExists())
                        {
                            cbEditor* newEd = Open(fname.GetFullPath());
                            if (newEd!=0L) // we found and were able to open it
                                return true; // --> RETURN
                        }
                    }
                }
            }
        }
        else // no opf
        {
            // build the directory list for further searching if opf not available
            for (int i = 0; i < project->GetFilesCount(); ++i)
            {
                ProjectFile* pf = project->GetFile(i);
                if (!pf)
                    continue;
                wxString dir = pf->file.GetPath(wxPATH_GET_VOLUME);
                if (dirs.Index(dir) == wxNOT_FOUND)
                    dirs.Add(dir);
            }
        }
        // if not found, continue building the list of directories for further searching
        // get targets include dirs
        for (int i = 0; i < project->GetBuildTargetsCount(); ++i)
        {
            ProjectBuildTarget* target = project->GetBuildTarget(i);
            if (target)
            {
                for (unsigned int ti = 0; ti < target->GetIncludeDirs().GetCount(); ++ti)
                {
                    // TODO (Morten#5#): target include dirs might override project include dirs, take append/prepend option into account
                    wxString dir = target->GetIncludeDirs()[ti];
                    if (dirs.Index(dir) == wxNOT_FOUND)
                        dirs.Add(dir);
                }
            }
        }
    } // project
    wxFileName fname;
    wxFileName fn(ed->GetFilename());
    dirs.Insert(fn.GetPath(wxPATH_GET_VOLUME), 0); // add file's dir
    for (unsigned int i = 0; i < dirs.GetCount(); ++i)
    {
        ProjectManager *pm = Manager::Get()->GetProjectManager();
        if ( !pm )
            break;
        wxString dir = dirs[i]; // might contain macros -> replace them
        Manager::Get()->GetMacrosManager()->ReplaceMacros(dir);
        fname.Assign(dir + wxFileName::GetPathSeparator() + fn.GetFullName());
//        Manager::Get()->GetLogManager()->DebugLog(F(_T("Looking for '%s', dir='%s'."), fname.GetFullPath().c_str(), dir.c_str()));
        if (!fname.IsAbsolute() && project)
        {
            fname.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, project->GetBasePath());
//            Manager::Get()->GetLogManager()->DebugLog(F(_T("Normalizing dir to '%s'."), fname.GetFullPath().c_str()));
        }
        wxString HeaderSource = pm->GetHeaderSource(fname);
        if (!HeaderSource.IsEmpty())
        {
            fname.SetFullName(HeaderSource);
//            Manager::Get()->GetLogManager()->DebugLog(F(_T("Located '%s'."), fname.GetFullPath().c_str()));
            break;
        }
    }
    if (fname.FileExists())
    {
        //Manager::Get()->GetLogManager()->DebugLog("ed=%s, pair=%s", ed->GetFilename().c_str(), pair.c_str());
        cbEditor* newEd = Open(fname.GetFullPath());
        if (newEd!=0L) // we found and were able to open it
            return true; // --> RETURN;
    }
    // We couldn't find the file, maybe it does not exist. Ask the user if we
    // should create it:
    if (cbMessageBox(_("The file seems not to exist. Do you want to create it?"),
                _("Error"), wxICON_QUESTION | wxYES_NO) == wxID_YES)
    {
        cbProject* project = Manager::Get()->GetProjectManager()->GetActiveProject();
        if (project)
            wxSetWorkingDirectory(project->GetBasePath());
        // Create a suggestion for the new file name:
        if (ft == ftHeader)
            fn.SetExt(FileFilters::CPP_EXT);
        else if (ft == ftSource)
            fn.SetExt(FileFilters::H_EXT);
        // else? Well, if the filename is not changed we could possibly
        // overwrite an existing file with our suggestion.
        cbEditor* newEd = New(fn.GetFullPath());
        if (project)
        {
            if (cbMessageBox(_("Do you want to add this new file in the active project?"),
                        _("Add file to project"),
                        wxYES_NO | wxICON_QUESTION) == wxID_YES)
            {
                wxArrayInt targets;
                if (Manager::Get()->GetProjectManager()->AddFileToProject(newEd->GetFilename(), project, targets) != 0)
                {
                    ProjectFile* pf = project->GetFileByFilename(newEd->GetFilename(), false);
                    newEd->SetProjectFile(pf);
                    Manager::Get()->GetProjectManager()->RebuildTree();
                }
            }
        }
        // verify that the open files are still in sync
        // the new file might have overwritten an existing one)
        Manager::Get()->GetEditorManager()->CheckForExternallyModifiedFiles();
    }
    return false;
}
Having a quick look at the code, I think the issue I'm encountering is due to the fact that the directory is not being taken in to account, both the first (searching open files) and second (searching the project) seem to rely on filename only (i.e. not the relative path to the file).
Going back to my original example:
root
-- subdir1
    Config.cpp
    Config.h
-- subdir2
    Config.cpp
    Config.h
-- subdir3
    Config.cpp
    Config.hIf I open Config.cpp in either subdir1 or subdir2 with no other files open and hit 'swap...' Config.h in subdir1 is opened, I assume because the second search (the one through the project) is matching on 'Config.' without paying attention to the directory in which it resides.
Similarly, if I have Config.h from subdir1 open and Config.cpp from subdir3 open, if I hit 'swap..' on Config.h from subdir1, it switches to Config.cpp from subdir3 because it's matching on 'Config' (based on the first search which uses the open files).
I think for my issue the relative path must be taken into consideration.