//------------------------------------------------------------------------------ wxString WizCompilerPanel::GetCompilerID() const { Compiler* compiler = CompilerFactory::GetCompilerByName(m_pCompilerPanel->GetCompilerCombo()->GetStringSelection()); if (compiler) return compiler->GetID(); return wxEmptyString; }
Compiler* CompilerFactory::CreateCompilerCopy(Compiler* compiler, const wxString& newName) { if (!compiler) return nullptr; // abort if an existing compiler with the same name exists // this also avoids the possibility of throwing an exception // in the compiler->CreateCopy() call below... for (size_t i = 0; i < Compilers.GetCount(); ++i) { if (Compilers[i]->GetName() == newName) return nullptr; } Compiler* newC = compiler->CreateCopy(); if (!newName.IsEmpty()) { Compiler::m_CompilerIDs.Remove(newC->GetID()); newC->SetName(newName); newC->m_ID = newName; newC->MakeValidID(); } newC->ReloadOptions(); RegisterCompiler(newC); newC->LoadSettings(_T("/user_sets")); Manager::Get()->GetLogManager()->DebugLog(F(_T("Added compiler \"%s\""), newC->GetName().wx_str())); return newC; // return the index for the new compiler }
//------------------------------------------------------------------------------ wxString WizBuildTargetPanel::GetCompilerID() const { if (!m_pBuildTargetPanel->GetCompilerCombo()->IsShown()) return wxEmptyString; Compiler* compiler = CompilerFactory::GetCompilerByName(m_pBuildTargetPanel->GetCompilerCombo()->GetStringSelection()); if (compiler) return compiler->GetID(); return wxEmptyString; }
WizBuildTargetPanel::WizBuildTargetPanel(const wxString& targetName, bool isDebug, wxWizard* parent, const wxBitmap& bitmap, bool showCompiler, const wxString& compilerID, const wxString& validCompilerIDs, bool allowCompilerChange) : WizPageBase(_T("BuildTargetPage"), parent, bitmap) { m_pBuildTargetPanel = new BuildTargetPanel(this); m_pBuildTargetPanel->SetTargetName(targetName); m_pBuildTargetPanel->SetEnableDebug(isDebug); m_pBuildTargetPanel->ShowCompiler(showCompiler); if (showCompiler) { wxArrayString valids = GetArrayFromString(validCompilerIDs, _T(";"), true); wxString def = compilerID; if (def.IsEmpty()) def = CompilerFactory::GetDefaultCompiler()->GetName(); int id = 0; wxComboBox* cmb = m_pBuildTargetPanel->GetCompilerCombo(); cmb->Clear(); for (size_t i = 0; i < CompilerFactory::GetCompilersCount(); ++i) { for (size_t n = 0; n < valids.GetCount(); ++n) { Compiler* compiler = CompilerFactory::GetCompiler(i); if (compiler) { if (compiler->GetID().Matches(valids[n])) { cmb->Append(compiler->GetName()); if (compiler->GetID().IsSameAs(def)) id = cmb->GetCount(); break; } } } } cmb->SetSelection(id); cmb->Enable(allowCompilerChange); } }
WizCompilerPanel::WizCompilerPanel(const wxString& compilerID, const wxString& validCompilerIDs, wxWizard* parent, const wxBitmap& bitmap, bool allowCompilerChange, bool allowConfigChange) : WizPageBase(_T("CompilerPage"), parent, bitmap), m_AllowConfigChange(allowConfigChange) { m_pCompilerPanel = new CompilerPanel(this, GetParent()); wxArrayString valids = GetArrayFromString(validCompilerIDs, _T(";"), true); wxString def = compilerID; if (def.IsEmpty()) def = CompilerFactory::GetDefaultCompilerID(); int id = 0; wxComboBox* cmb = m_pCompilerPanel->GetCompilerCombo(); cmb->Clear(); for (size_t i = 0; i < CompilerFactory::GetCompilersCount(); ++i) { Compiler* compiler = CompilerFactory::GetCompiler(i); if (compiler) { for (size_t n = 0; n < valids.GetCount(); ++n) { // match not only if IDs match, but if ID inherits from it too if (CompilerFactory::CompilerInheritsFrom(compiler, valids[n])) { cmb->Append(compiler->GetName()); if (compiler->GetID().IsSameAs(def)) id = (cmb->GetCount() - 1) < 0 ? 0 : (cmb->GetCount() - 1); break; } } } } cmb->SetSelection(id); cmb->Enable(allowCompilerChange); m_pCompilerPanel->EnableConfigurationTargets(m_AllowConfigChange); ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("scripts")); m_pCompilerPanel->SetWantDebug(cfg->ReadBool(_T("/generic_wizard/want_debug"), true)); m_pCompilerPanel->SetDebugName(cfg->Read(_T("/generic_wizard/debug_name"), _T("Debug"))); m_pCompilerPanel->SetDebugOutputDir(cfg->Read(_T("/generic_wizard/debug_output"), _T("bin") + wxString(wxFILE_SEP_PATH) + _T("Debug"))); m_pCompilerPanel->SetDebugObjectOutputDir(cfg->Read(_T("/generic_wizard/debug_objects_output"), _T("obj") + wxString(wxFILE_SEP_PATH) + _T("Debug"))); m_pCompilerPanel->SetWantRelease(cfg->ReadBool(_T("/generic_wizard/want_release"), true)); m_pCompilerPanel->SetReleaseName(cfg->Read(_T("/generic_wizard/release_name"), _T("Release"))); m_pCompilerPanel->SetReleaseOutputDir(cfg->Read(_T("/generic_wizard/release_output"), _T("bin") + wxString(wxFILE_SEP_PATH) + _T("Release"))); m_pCompilerPanel->SetReleaseObjectOutputDir(cfg->Read(_T("/generic_wizard/release_objects_output"), _T("obj") + wxString(wxFILE_SEP_PATH) + _T("Release"))); }
// Don't call this function from within the scope of: // ClangPlugin::OnEditorHook // ClangPlugin::OnTimer int ClangPlugin::UpdateCompileCommand(cbEditor* ed) { wxString compileCommand; ProjectFile* pf = ed->GetProjectFile(); m_UpdateCompileCommand++; if ( m_UpdateCompileCommand > 1 ) { // Re-entry is not allowed m_UpdateCompileCommand--; return 0; } ProjectBuildTarget* target = nullptr; Compiler* comp = nullptr; if (pf && pf->GetParentProject() && !pf->GetBuildTargets().IsEmpty()) { target = pf->GetParentProject()->GetBuildTarget(pf->GetBuildTargets()[0]); comp = CompilerFactory::GetCompiler(target->GetCompilerID()); } cbProject* proj = (pf ? pf->GetParentProject() : nullptr); if ( (!comp) && proj) comp = CompilerFactory::GetCompiler(proj->GetCompilerID()); if (!comp) { cbProject* tmpPrj = Manager::Get()->GetProjectManager()->GetActiveProject(); if (tmpPrj) comp = CompilerFactory::GetCompiler(tmpPrj->GetCompilerID()); } if (!comp) comp = CompilerFactory::GetDefaultCompiler(); if (pf && (!pf->GetBuildTargets().IsEmpty()) ) { target = pf->GetParentProject()->GetBuildTarget(pf->GetBuildTargets()[0]); if (pf->GetUseCustomBuildCommand(target->GetCompilerID() )) compileCommand = pf->GetCustomBuildCommand(target->GetCompilerID()).AfterFirst(wxT(' ')); } if (compileCommand.IsEmpty()) compileCommand = wxT("$options $includes"); CompilerCommandGenerator* gen = comp->GetCommandGenerator(proj); if (gen) gen->GenerateCommandLine(compileCommand, target, pf, ed->GetFilename(), g_InvalidStr, g_InvalidStr, g_InvalidStr ); delete gen; wxStringTokenizer tokenizer(compileCommand); compileCommand.Empty(); wxString pathStr; while (tokenizer.HasMoreTokens()) { wxString flag = tokenizer.GetNextToken(); // make all include paths absolute, so clang does not choke if Code::Blocks switches directories if (flag.StartsWith(wxT("-I"), &pathStr)) { wxFileName path(pathStr); if (path.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE)) flag = wxT("-I") + path.GetFullPath(); } compileCommand += flag + wxT(" "); } compileCommand += GetCompilerInclDirs(comp->GetID()); m_UpdateCompileCommand--; if (compileCommand != m_CompileCommand) { m_CompileCommand = compileCommand; return 1; } return 0; }
AutoDetectCompilers::AutoDetectCompilers(wxWindow* parent) { //ctor wxXmlResource::Get()->LoadObject(this, parent, _T("dlgAutoDetectCompilers"),_T("wxScrollingDialog")); wxListCtrl* list = XRCCTRL(*this, "lcCompilers", wxListCtrl); if (list) { list->Connect(wxEVT_MOTION, wxMouseEventHandler(AutoDetectCompilers::OnMouseMotion)); list->ClearAll(); list->InsertColumn(0, _("Compiler"), wxLIST_FORMAT_LEFT, 380); list->InsertColumn(1, _("Status"), wxLIST_FORMAT_LEFT, 100); for (size_t i = 0; i < CompilerFactory::GetCompilersCount(); ++i) { Compiler* compiler = CompilerFactory::GetCompiler(i); if (!compiler) continue; list->InsertItem(list->GetItemCount(), compiler->GetName()); wxString path = compiler->GetMasterPath(); wxString path_no_macros = compiler->GetMasterPath(); Manager::Get()->GetMacrosManager()->ReplaceMacros(path_no_macros); int idx = list->GetItemCount() - 1; int highlight = 0; if (path.IsEmpty() && Manager::Get()->GetConfigManager(wxT("compiler"))->Exists(wxT("/sets/") + compiler->GetID() + wxT("/name"))) { // Here, some user-interaction is required not to show this // dialog again on each new start-up of C::B. list->SetItem(idx, 1, _("Invalid")); // So we better clearly HIGHLIGHT this entry: highlight = 1; } else // The compiler is *probably* invalid, but at least a master-path is set { list->SetItem(idx, 1, _("Not found")); highlight = -1; } // Inspect deeper and probably try to auto-detect invalid compilers: if (compiler->GetParentID().IsEmpty()) // built-in compiler { // Try auto-detection (which is for built-in compilers only) bool detected = compiler->AutoDetectInstallationDir() == adrDetected; wxString pathDetected( compiler->GetMasterPath() ); // In case auto-detection was successful: if (detected) { // No path setup before OR path detected as it was setup before if (path.IsEmpty() || path == pathDetected || path_no_macros == pathDetected) list->SetItem(idx, 1, _("Detected")); // OK else list->SetItem(idx, 1, _("User-defined")); // OK highlight = 0; } // In case auto-detection failed but a path was setup before: else if ( !path.IsEmpty() ) { // Check, if the master path is valid: if ( wxFileName::DirExists(path_no_macros) && !(path == pathDetected || path_no_macros == pathDetected) ) { list->SetItem(idx, 1, _("User-defined")); // OK highlight = 0; } // Assume the user did the setup on purpose, so reset the old settings anyways: compiler->SetMasterPath(path); } } else // no built-in, but user-defined (i.e. copied) compiler { // Check, if the master path is valid: if ( !path.IsEmpty() && wxFileName::DirExists(path_no_macros) ) { list->SetItem(idx, 1, _("User-defined")); // OK highlight = 0; } } if (highlight == 1) list->SetItemBackgroundColour(idx, *wxRED); else if (highlight == -1) list->SetItemTextColour(idx, *wxLIGHT_GREY); } // Resize columns so one can read the whole stuff: list->SetColumnWidth(0, wxLIST_AUTOSIZE); list->SetColumnWidth(1, wxLIST_AUTOSIZE); } XRCCTRL(*this, "lblDefCompiler", wxStaticText)->SetLabel(CompilerFactory::GetDefaultCompiler()->GetName()); }
wxArrayString DirectCommands::GetCompileFileCommand(ProjectBuildTarget* target, ProjectFile* pf) { wxArrayString ret; wxArrayString retGenerated; // is it compilable? if (!pf->compile || pf->compilerVar.IsEmpty()) return ret; const pfDetails& pfd = pf->GetFileDetails(target); Compiler* compiler = target ? CompilerFactory::GetCompiler(target->GetCompilerID()) : m_pCompiler; // wxString Object = (compiler->GetSwitches().UseFlatObjects)?pfd.object_file_flat:pfd.object_file; wxString Object = (target->GetUseFlatObjects())?pfd.object_file_flat:pfd.object_file; // lookup file's type FileType ft = FileTypeOf(pf->relativeFilename); // create output dir if (!pfd.object_dir_native.IsEmpty() && !CreateDirRecursively(pfd.object_dir_native, 0755)) { cbMessageBox(_("Can't create object output directory ") + pfd.object_dir_native); } bool isResource = ft == ftResource; bool isHeader = ft == ftHeader; // allowed resources under all platforms: makes sense when cross-compiling for // windows under linux. // and anyway, if the user is dumb enough to try to compile resources without // having a resource compiler, (s)he deserves the upcoming build error ;) //#ifndef __WXMSW__ // // not supported under non-win32 platforms // if (isResource) // return ret; //#endif wxString compilerCmd,source_file,tempCompilerCmd(wxEmptyString); if (!isHeader || compiler->GetSwitches().supportsPCH) { const CompilerTool& tool = compiler->GetCompilerTool(isResource ? ctCompileResourceCmd : ctCompileObjectCmd, pf->file.GetExt()); // does it generate other files to compile? for (size_t i = 0; i < pf->generatedFiles.size(); ++i) { AppendArray(GetCompileFileCommand(target, pf->generatedFiles[i]), retGenerated); // recurse } pfCustomBuild& pcfb = pf->customBuild[compiler->GetID()]; compilerCmd = pcfb.useCustomBuildCommand ? pcfb.buildCommand : tool.command; if (target->GetUseFullSourcePaths()) { source_file = UnixFilename(pfd.source_file_absolute_native); // for resource files, use short from if path because if windres bug with spaces-in-paths if (isResource) source_file = pf->file.GetShortPath(); } else source_file = pfd.source_file; QuoteStringIfNeeded(source_file); compiler->GenerateCommandLine(compilerCmd, target, pf, source_file, Object, pfd.object_file_flat, pfd.dep_file); } if (!compilerCmd.IsEmpty()) // my lcy 1 { switch (compiler->GetSwitches().logging) { case clogFull: ret.Add(wxString(COMPILER_SIMPLE_LOG) + compilerCmd); break; case clogSimple: if (isHeader) ret.Add(wxString(COMPILER_SIMPLE_LOG) + _("Precompiling header: ") + pfd.source_file_native); else ret.Add(wxString(COMPILER_SIMPLE_LOG) + _("Compiling: ") + pfd.source_file_native); break; default: break; } AddCommandsToArray(compilerCmd, ret); if(m_pCurrTarget->GetGenerateEachLit()) AddCommandsToArray(GenerateLitForEachObj(Object,compiler->GetPrograms().OBJDUMP),ret); if (isHeader) ret.Add(wxString(COMPILER_WAIT)); if (retGenerated.GetCount()) { // not only append commands for (any) generated files to be compiled // but also insert a "pause" to allow this file to generate its files first if (!isHeader) // if isHeader, the "pause" has already been added ret.Add(wxString(COMPILER_WAIT)); AppendArray(retGenerated, ret); } // if it's a PCH, delete the previously generated PCH to avoid problems // (it 'll be recreated anyway) if (FileTypeOf(pf->relativeFilename) == ftHeader && pf->compile) { wxString ObjectAbs = (m_pCurrTarget->GetUseFlatObjects())?pfd.object_file_flat_absolute_native:pfd.object_file_absolute_native; wxRemoveFile(ObjectAbs); } } else // lcy skip { ret.Add(wxString(COMPILER_SIMPLE_LOG) + _("Skipping file (no compiler program set): ") + pfd.source_file_native); } return ret; }
wxArrayString DirectCommands::GetCompileFileCommand(ProjectBuildTarget* target, ProjectFile* pf) const { wxArrayString ret; wxArrayString ret_generated; // is it compilable? if (!pf || !pf->compile) return ret; if (pf->compilerVar.IsEmpty()) { Manager::Get()->GetLogManager()->DebugLog(_("Cannot resolve compiler var for project file.")); return ret; } Compiler* compiler = target ? CompilerFactory::GetCompiler(target->GetCompilerID()) : m_pCompiler; if (!compiler) { Manager::Get()->GetLogManager()->DebugLog(_("Can't access compiler for file.")); return ret; } const pfDetails& pfd = pf->GetFileDetails(target); wxString object = (compiler->GetSwitches().UseFlatObjects) ? pfd.object_file_flat : pfd.object_file; wxString object_dir = (compiler->GetSwitches().UseFlatObjects) ? pfd.object_dir_flat_native : pfd.object_dir_native; // create output dir if (!object_dir.IsEmpty() && !CreateDirRecursively(object_dir, 0755)) Manager::Get()->GetLogManager()->DebugLog(_("Can't create object output directory:\n") + object_dir); // lookup file's type const FileType ft = FileTypeOf(pf->relativeFilename); bool is_resource = ft == ftResource; bool is_header = ft == ftHeader; // allowed resources under all platforms: makes sense when cross-compiling for // windows under linux. // and anyway, if the user is dumb enough to try to compile resources without // having a resource compiler, (s)he deserves the upcoming build error ;) wxString compiler_cmd; if (!is_header || compiler->GetSwitches().supportsPCH) { const CompilerTool* tool = compiler->GetCompilerTool(is_resource ? ctCompileResourceCmd : ctCompileObjectCmd, pf->file.GetExt()); // does it generate other files to compile? for (size_t i = 0; i < pf->generatedFiles.size(); ++i) AppendArray(GetCompileFileCommand(target, pf->generatedFiles[i]), ret_generated); // recurse pfCustomBuild& pcfb = pf->customBuild[compiler->GetID()]; if (pcfb.useCustomBuildCommand) compiler_cmd = pcfb.buildCommand; else if (tool) compiler_cmd = tool->command; else compiler_cmd = wxEmptyString; wxString source_file; if (compiler->GetSwitches().UseFullSourcePaths) source_file = UnixFilename(pfd.source_file_absolute_native); else source_file = pfd.source_file; #ifdef command_line_generation Manager::Get()->GetLogManager()->DebugLog(F(_T("GetCompileFileCommand[1]: compiler_cmd='%s', source_file='%s', object='%s', object_dir='%s'."), compiler_cmd.wx_str(), source_file.wx_str(), object.wx_str(), object_dir.wx_str())); #endif // for resource files, use short from if path because if windres bug with spaces-in-paths if (is_resource && compiler->GetSwitches().UseFullSourcePaths) source_file = pf->file.GetShortPath(); QuoteStringIfNeeded(source_file); #ifdef command_line_generation Manager::Get()->GetLogManager()->DebugLog(F(_T("GetCompileFileCommand[2]: source_file='%s'."), source_file.wx_str())); #endif m_pGenerator->GenerateCommandLine(compiler_cmd, target, pf, source_file, object, pfd.object_file_flat, pfd.dep_file); } if (!is_header && compiler_cmd.IsEmpty()) { ret.Add(COMPILER_SIMPLE_LOG + _("Skipping file (no compiler program set): ") + pfd.source_file_native ); return ret; } switch (compiler->GetSwitches().logging) { case clogFull: ret.Add(COMPILER_SIMPLE_LOG + compiler_cmd); break; case clogSimple: if (is_header) ret.Add(COMPILER_SIMPLE_LOG + _("Pre-compiling header: ") + pfd.source_file_native ); else ret.Add(COMPILER_SIMPLE_LOG + _("Compiling: ") + pfd.source_file_native ); break; case clogNone: // fall-through default: break; } AddCommandsToArray(compiler_cmd, ret); if (is_header) ret.Add(COMPILER_WAIT); if (ret_generated.GetCount()) { // not only append commands for (any) generated files to be compiled // but also insert a "pause" to allow this file to generate its files first if (!is_header) // if is_header, the "pause" has already been added ret.Add(COMPILER_WAIT); AppendArray(ret_generated, ret); } // if it's a PCH, delete the previously generated PCH to avoid problems // (it 'll be recreated anyway) if ( (ft == ftHeader) && pf->compile ) { wxString object_abs = (compiler->GetSwitches().UseFlatObjects) ? pfd.object_file_flat_absolute_native : pfd.object_file_absolute_native; if ( wxFileExists(object_abs) && !wxRemoveFile(object_abs) ) Manager::Get()->GetLogManager()->DebugLog(_("Cannot remove old PCH file:\n") + object_abs); } return ret; }
void ClangPlugin::OnTimer(wxTimerEvent& event) { if (!IsAttached()) return; const int evId = event.GetId(); if (evId == idEdOpenTimer) { cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); if (!ed || !IsProviderFor(ed)) return; else if (m_Proxy.GetTranslationUnitId(ed->GetFilename()) != wxNOT_FOUND) { m_DiagnosticTimer.Start(DIAGNOSTIC_DELAY, wxTIMER_ONE_SHOT); return; } wxString compileCommand; ProjectFile* pf = ed->GetProjectFile(); ProjectBuildTarget* target = nullptr; Compiler* comp = nullptr; if (pf && pf->GetParentProject() && !pf->GetBuildTargets().IsEmpty() ) { target = pf->GetParentProject()->GetBuildTarget(pf->GetBuildTargets()[0]); comp = CompilerFactory::GetCompiler(target->GetCompilerID()); if (pf->GetUseCustomBuildCommand(target->GetCompilerID())) { compileCommand = pf->GetCustomBuildCommand(target->GetCompilerID()).AfterFirst(wxT(' ')); } } if (compileCommand.IsEmpty()) compileCommand = wxT("$options $includes"); cbProject* proj = (pf ? pf->GetParentProject() : nullptr); if (!comp && proj) comp = CompilerFactory::GetCompiler(proj->GetCompilerID()); if (!comp) { cbProject* tmpPrj = Manager::Get()->GetProjectManager()->GetActiveProject(); if (tmpPrj) comp = CompilerFactory::GetCompiler(tmpPrj->GetCompilerID()); } if (!comp) comp = CompilerFactory::GetDefaultCompiler(); comp->GetCommandGenerator(proj)->GenerateCommandLine(compileCommand, target, pf, ed->GetFilename(), g_InvalidStr, g_InvalidStr, g_InvalidStr ); wxStringTokenizer tokenizer(compileCommand); compileCommand.Empty(); wxString pathStr; while (tokenizer.HasMoreTokens()) { wxString flag = tokenizer.GetNextToken(); // make all include paths absolute, so clang does not choke if Code::Blocks switches directories if (flag.StartsWith(wxT("-I"), &pathStr)) { wxFileName path(pathStr); if (path.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE)) flag = wxT("-I") + path.GetFullPath(); } compileCommand += flag + wxT(" "); } compileCommand += GetCompilerInclDirs(comp->GetID()); if (FileTypeOf(ed->GetFilename()) == ftHeader) // try to find the associated source { const wxString& source = GetSourceOf(ed); if (!source.IsEmpty()) { m_Proxy.CreateTranslationUnit(source, compileCommand); if (m_Proxy.GetTranslationUnitId(ed->GetFilename()) != wxNOT_FOUND) return; // got it } } m_Proxy.CreateTranslationUnit(ed->GetFilename(), compileCommand); m_DiagnosticTimer.Start(DIAGNOSTIC_DELAY, wxTIMER_ONE_SHOT); } else if (evId == idReparseTimer) { EditorManager* edMgr = Manager::Get()->GetEditorManager(); cbEditor* ed = edMgr->GetBuiltinActiveEditor(); if (!ed) return; if (ed != m_pLastEditor) { m_TranslUnitId = m_Proxy.GetTranslationUnitId(ed->GetFilename()); m_pLastEditor = ed; } if (m_TranslUnitId == wxNOT_FOUND) return; std::map<wxString, wxString> unsavedFiles; for (int i = 0; i < edMgr->GetEditorsCount(); ++i) { ed = edMgr->GetBuiltinEditor(i); if (ed && ed->GetModified()) unsavedFiles.insert(std::make_pair(ed->GetFilename(), ed->GetControl()->GetText())); } m_Proxy.Reparse(m_TranslUnitId, unsavedFiles); DiagnoseEd(m_pLastEditor, dlMinimal); } else if (evId == idDiagnosticTimer) { cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor(); if (!ed) return; if (ed != m_pLastEditor) { m_TranslUnitId = m_Proxy.GetTranslationUnitId(ed->GetFilename()); m_pLastEditor = ed; } if (m_TranslUnitId == wxNOT_FOUND) return; DiagnoseEd(ed, dlFull); } else event.Skip(); }