mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-30 12:25:35 +02:00
Patch for Bogdan Gheorghe:
Indexer ======= - Changed file extensions to prevent header files from being indexed (they will be indexed via inclusion) Search ======= - Added scope checking to MatchLocator - Modified CSearchPattern to allow for destructor searches - Added debug tracing statements to SearchEngine - Added debug tracing statements to MatchLocator UI == - Converted CTags based OpenOnSelectionAction to OpenDeclarationsAction. For now, we do a search on all types with the selected name. - Hooked up OpenDeclarationsAction to search engine General ======= - Modified start up code to set debug trace options (which are defined from the launcher). I've added the following trace components: - dependency - indexer - indexmanager - matchlocator - model - search - parser - Added trace debug statements to CModelBuilder - Modified Util.java to make use of IDebugLogConstants
This commit is contained in:
parent
eb6f0a3264
commit
8f3b6007eb
23 changed files with 417 additions and 320 deletions
|
@ -202,6 +202,7 @@ public class IndexManagerTests extends TestCase {
|
|||
assertTrue("Index exists for project",ind != null);
|
||||
//Add a new file to the project, give it some time to index
|
||||
importFile("DocumentManager.h","resources/indexer/DocumentManager.h");
|
||||
importFile("DocumentManager.cpp","resources/indexer/DocumentManager.cpp");
|
||||
Thread.sleep(10000);
|
||||
ind = indexManager.getIndex(testProjectPath,true,true);
|
||||
char[] prefix = "typeDecl/C/CDocumentManager".toCharArray();
|
||||
|
@ -499,7 +500,7 @@ public class IndexManagerTests extends TestCase {
|
|||
|
||||
public void testForwardDeclarations() throws Exception{
|
||||
//Add a new file to the project, give it some time to index
|
||||
importFile("refTest.cpp","resources/indexer/refTest.cpp");
|
||||
importFile("reftest.cpp","resources/indexer/reftest.cpp");
|
||||
//Enable indexing on the created project
|
||||
//By doing this, we force the Index Manager to indexAll()
|
||||
indexManager = CCorePlugin.getDefault().getCoreModel().getIndexManager();
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
#include "StdAfx.h"
|
||||
#include "documentmanager.h"
|
||||
|
||||
CDocumentManager::CDocumentManager(void)
|
||||
{
|
||||
}
|
||||
|
||||
CDocumentManager::~CDocumentManager(void)
|
||||
{
|
||||
}
|
||||
|
||||
void CDocumentManager::addToControlMap(UINT threadID, IUnknown * theControl)
|
||||
{
|
||||
_controlMap.insert(MUL2IUnk_Pair(threadID,theControl));
|
||||
}
|
||||
|
||||
void CDocumentManager::getControl(ULONG threadID, IUnknown ** theControl)
|
||||
{
|
||||
if (_controlMap.find(threadID) != _controlMap.end())
|
||||
{
|
||||
theControl = &_controlMap[threadID];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//#include "StdAfx.h"
|
||||
#include "documentmanager.h"
|
||||
|
||||
CDocumentManager::CDocumentManager(void)
|
||||
{
|
||||
}
|
||||
|
||||
CDocumentManager::~CDocumentManager(void)
|
||||
{
|
||||
}
|
||||
|
||||
void CDocumentManager::addToControlMap(UINT threadID, IUnknown * theControl)
|
||||
{
|
||||
_controlMap.insert(MUL2IUnk_Pair(threadID,theControl));
|
||||
}
|
||||
|
||||
void CDocumentManager::getControl(ULONG threadID, IUnknown ** theControl)
|
||||
{
|
||||
if (_controlMap.find(threadID) != _controlMap.end())
|
||||
{
|
||||
theControl = &_controlMap[threadID];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +1,22 @@
|
|||
org.eclipse.cdt.core/debug=true
|
||||
org.eclipse.cdt.core/debug=true
|
||||
|
||||
# Reports model builder activity
|
||||
org.eclipse.cdt.core/debug/model=false
|
||||
|
||||
# Reports parser activity
|
||||
org.eclipse.cdt.core/debug/parser=false
|
||||
|
||||
# Reports background indexer activity: indexing, saving index file, index queries
|
||||
org.eclipse.cdt.core/debug/indexmanager=false
|
||||
|
||||
# Reports search activity
|
||||
org.eclipse.cdt.core/debug/search=false
|
||||
|
||||
# Reports encoded index entries
|
||||
org.eclipse.cdt.core/debug/indexer=false
|
||||
|
||||
# Reports search matches
|
||||
org.eclipse.cdt.core/debug/matchlocator=false
|
||||
|
||||
# Reports background dependency tree activity
|
||||
org.eclipse.cdt.core/debug/dependency=false
|
|
@ -1,3 +1,11 @@
|
|||
2003-08-26 Bogdan Gheorghe
|
||||
- Modified start up code to set debug trace options
|
||||
- Added trace debug statements to CModelBuilder.
|
||||
- Added IDebugLogConstants which contain ids for all
|
||||
Util.debugLog clients (currently Parser and CModelBuidler)
|
||||
- Modified Util.java to make use of IDebugLogConstants
|
||||
|
||||
|
||||
2003-08-25 Hoda Amer
|
||||
Modified the IASTFactory to take three expression lists
|
||||
for the createNewDescriptor() instead of just one.
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2003-08-26 Bogdan Gheorghe
|
||||
- Removed header file extensions from being indexed (they
|
||||
will be indexed via inclusion)
|
||||
|
||||
2003-08-20 Bogdan Gheorghe
|
||||
- Added debug tracing in AbstractIndexer
|
||||
- Added additional file extensions to supported indexed files
|
||||
|
|
|
@ -43,7 +43,9 @@ import org.eclipse.core.resources.IProject;
|
|||
public class SourceIndexer extends AbstractIndexer {
|
||||
|
||||
//TODO: Indexer, add additional file types
|
||||
public static final String[] FILE_TYPES= new String[] {"cpp","h","c", "cc", "hh", "cxx", "hpp"}; //$NON-NLS-1$
|
||||
//Header files: "h" , "hh", "hpp"
|
||||
public static final String[] FILE_TYPES= new String[] {"cpp","c", "cc", "cxx"}; //$NON-NLS-1$
|
||||
|
||||
//protected DefaultProblemFactory problemFactory= new DefaultProblemFactory(Locale.getDefault());
|
||||
IFile resourceFile;
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ public class CModelBuilder {
|
|||
// For the debuglog to take place, you have to call
|
||||
// Util.setDebugging(true);
|
||||
// Or set debug to true in the core plugin preference
|
||||
Util.debugLog("CModel build: "+ ( System.currentTimeMillis() - startTime ) + "ms");
|
||||
Util.debugLog("CModel build: "+ ( System.currentTimeMillis() - startTime ) + "ms", IDebugLogConstants.MODEL);
|
||||
return this.newElements;
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Created on Aug 25, 2003
|
||||
*
|
||||
* To change the template for this generated file go to
|
||||
* Window>Preferences>Java>Code Generation>Code and Comments
|
||||
*/
|
||||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**
|
||||
* @author bgheorgh
|
||||
*
|
||||
* To change the template for this generated type comment go to
|
||||
* Window>Preferences>Java>Code Generation>Code and Comments
|
||||
*/
|
||||
public interface IDebugLogConstants {
|
||||
public class DebugLogConstant {
|
||||
private DebugLogConstant( int value )
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
private final int value;
|
||||
}
|
||||
|
||||
public static final DebugLogConstant PARSER = new DebugLogConstant( 1 );
|
||||
public static final DebugLogConstant MODEL = new DebugLogConstant ( 2 );
|
||||
|
||||
}
|
|
@ -15,16 +15,21 @@ import java.text.MessageFormat;
|
|||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICModelStatusConstants;
|
||||
import org.eclipse.cdt.internal.core.model.IDebugLogConstants.DebugLogConstant;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
|
||||
public class Util {
|
||||
|
||||
|
||||
public static boolean VERBOSE_PARSER = false;
|
||||
public static boolean VERBOSE_MODEL = false;
|
||||
|
||||
private Util() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static StringBuffer getContent(IFile file) throws IOException {
|
||||
InputStream stream = null;
|
||||
try {
|
||||
|
@ -173,9 +178,9 @@ public class Util {
|
|||
Util.log(status);
|
||||
}
|
||||
|
||||
public static void debugLog(String message) {
|
||||
public static void debugLog(String message, DebugLogConstant client) {
|
||||
if( CCorePlugin.getDefault() == null ) return;
|
||||
if ( CCorePlugin.getDefault().isDebugging()) {
|
||||
if ( CCorePlugin.getDefault().isDebugging() && isActive(client)) {
|
||||
// Time stamp
|
||||
message = MessageFormat.format( "[{0}] {1}", new Object[] { new Long( System.currentTimeMillis() ), message } );
|
||||
while (message.length() > 100) {
|
||||
|
@ -191,6 +196,20 @@ public class Util {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param client
|
||||
* @return
|
||||
*/
|
||||
private static boolean isActive(DebugLogConstant client) {
|
||||
if (client.equals(IDebugLogConstants.PARSER)){
|
||||
return VERBOSE_PARSER;
|
||||
}
|
||||
else if (client.equals(IDebugLogConstants.MODEL)){
|
||||
return VERBOSE_MODEL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void setDebugging(boolean value){
|
||||
CCorePlugin.getDefault().setDebugging(value);
|
||||
}
|
||||
|
@ -263,4 +282,5 @@ public class Util {
|
|||
}
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
2003-08-26 Bogdan Gheorghe
|
||||
Added parser constant to all debugLog tracing statements.
|
||||
|
||||
2003-08-25 John Camelon
|
||||
Fixed bug39526 - Parser doesn't handle initializers correctly.
|
||||
Fixed bug41520 - FullParse : Constructor Initializer is mistaken as function prototype
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Stack;
|
|||
import org.eclipse.cdt.core.parser.ISourceElementRequestor;
|
||||
import org.eclipse.cdt.core.parser.ScannerException;
|
||||
import org.eclipse.cdt.core.parser.ast.IASTInclusion;
|
||||
import org.eclipse.cdt.internal.core.model.IDebugLogConstants;
|
||||
import org.eclipse.cdt.internal.core.model.Util;
|
||||
|
||||
/**
|
||||
|
@ -86,7 +87,7 @@ public class ContextStack {
|
|||
try {
|
||||
currentContext.getReader().close();
|
||||
} catch (IOException ie) {
|
||||
Util.debugLog("ContextStack : Error closing reader ");
|
||||
Util.debugLog("ContextStack : Error closing reader ", IDebugLogConstants.PARSER);
|
||||
}
|
||||
|
||||
if( currentContext.getKind() == IScannerContext.INCLUSION )
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.eclipse.cdt.core.parser.ast.IASTUsingDeclaration;
|
|||
import org.eclipse.cdt.core.parser.ast.IASTUsingDirective;
|
||||
import org.eclipse.cdt.core.parser.ast.IASTClassSpecifier.ClassNameType;
|
||||
import org.eclipse.cdt.core.parser.ast.IASTExpression.Kind;
|
||||
import org.eclipse.cdt.internal.core.model.IDebugLogConstants;
|
||||
import org.eclipse.cdt.internal.core.model.Util;
|
||||
/**
|
||||
* This is our first implementation of the IParser interface, serving as a parser for
|
||||
|
@ -143,7 +144,7 @@ public class Parser implements IParser
|
|||
+ ": "
|
||||
+ (System.currentTimeMillis() - startTime)
|
||||
+ "ms"
|
||||
+ (parsePassed ? "" : " - parse failure"));
|
||||
+ (parsePassed ? "" : " - parse failure"), IDebugLogConstants.PARSER);
|
||||
return parsePassed;
|
||||
}
|
||||
public void onParseEnd()
|
||||
|
@ -1957,7 +1958,7 @@ public class Parser implements IParser
|
|||
failParse();
|
||||
Util.debugLog(
|
||||
"Unexpected Token ="
|
||||
+ image);
|
||||
+ image,IDebugLogConstants.PARSER);
|
||||
consume();
|
||||
// eat this token anyway
|
||||
continue;
|
||||
|
@ -4435,7 +4436,7 @@ public class Parser implements IParser
|
|||
}
|
||||
catch (ScannerException e)
|
||||
{
|
||||
Util.debugLog( "ScannerException thrown : " + e.getMessage() );
|
||||
Util.debugLog( "ScannerException thrown : " + e.getMessage(), IDebugLogConstants.PARSER );
|
||||
return fetchToken();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.eclipse.cdt.core.parser.ast.ExpressionEvaluationException;
|
|||
import org.eclipse.cdt.core.parser.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.parser.ast.IASTFactory;
|
||||
import org.eclipse.cdt.core.parser.ast.IASTInclusion;
|
||||
import org.eclipse.cdt.internal.core.model.IDebugLogConstants;
|
||||
import org.eclipse.cdt.internal.core.model.Util;
|
||||
|
||||
|
||||
|
@ -2139,7 +2140,7 @@ public class Scanner implements IScanner {
|
|||
BAD_PP + contextStack.getCurrentContext().getOffset());
|
||||
}
|
||||
} else {
|
||||
Util.debugLog("Scanner : Encountered unexpected character " + ((char) c));
|
||||
Util.debugLog("Scanner : Encountered unexpected character " + ((char) c), IDebugLogConstants.PARSER);
|
||||
if (throwExceptionOnBadPreprocessorSyntax)
|
||||
throw new ScannerException(BAD_PP + contextStack.getCurrentContext().getOffset());
|
||||
}
|
||||
|
@ -2333,7 +2334,7 @@ public class Scanner implements IScanner {
|
|||
} else {
|
||||
Util.debugLog(
|
||||
"Unexpected class stored in definitions table. "
|
||||
+ expansion.getClass().getName());
|
||||
+ expansion.getClass().getName(), IDebugLogConstants.PARSER);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2003-08-26 Bogdan Gheorghe
|
||||
- Added debug tracing statements to SearchEngine
|
||||
- Modified scanForNames in CSearchPattern to treat append
|
||||
a token after "~" to allow for destructors search
|
||||
- Added scope checking to MatchLocator
|
||||
- Added debug trace statements to MatchLocator
|
||||
|
||||
2003-08-20 Bogdan Gheorghe
|
||||
- Changed matching and reporting functions to handle nodes
|
||||
of type IElaboratedTypeSpecifier
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.eclipse.core.runtime.SubProgressMonitor;
|
|||
*/
|
||||
public class SearchEngine implements ICSearchConstants{
|
||||
|
||||
private boolean VERBOSE = false;
|
||||
public static boolean VERBOSE = false;
|
||||
|
||||
/**
|
||||
* A list of working copies that take precedence over their original
|
||||
|
|
|
@ -354,7 +354,10 @@ public abstract class CSearchPattern implements ICSearchConstants, ICSearchPatte
|
|||
name = new String("");
|
||||
break;
|
||||
default:
|
||||
if( token.getType() == IToken.tSTAR || token.getType() == IToken.tQUESTION ){
|
||||
if( token.getType() == IToken.tSTAR ||
|
||||
token.getType() == IToken.tQUESTION ||
|
||||
token.getType() == IToken.tCOMPL //Need this for destructors
|
||||
){
|
||||
lastTokenWasWild = true;
|
||||
} else if( !lastTokenWasWild && name.length() > 0 ) {
|
||||
name += " ";
|
||||
|
|
|
@ -91,6 +91,8 @@ import org.eclipse.core.runtime.Path;
|
|||
*/
|
||||
public class MatchLocator implements ISourceElementRequestor, ICSearchConstants {
|
||||
|
||||
|
||||
public static boolean VERBOSE = false;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -301,6 +303,8 @@ public class MatchLocator implements ISourceElementRequestor, ICSearchConstants
|
|||
//skip duplicates
|
||||
if( i > 0 && pathString.equals( paths[ i - 1 ] ) ) continue;
|
||||
|
||||
if (!searchScope.encloses(pathString)) continue;
|
||||
|
||||
Reader reader = null;
|
||||
|
||||
IPath realPath = null;
|
||||
|
@ -355,6 +359,9 @@ public class MatchLocator implements ISourceElementRequestor, ICSearchConstants
|
|||
IScanner scanner = ParserFactory.createScanner( reader, realPath.toOSString(), scanInfo, ParserMode.COMPLETE_PARSE, this );
|
||||
IParser parser = ParserFactory.createParser( scanner, this, ParserMode.COMPLETE_PARSE );
|
||||
|
||||
if (VERBOSE)
|
||||
MatchLocator.verbose("*** New Search for path: " + pathString);
|
||||
|
||||
parser.parse();
|
||||
}
|
||||
}
|
||||
|
@ -368,11 +375,15 @@ public class MatchLocator implements ISourceElementRequestor, ICSearchConstants
|
|||
IASTReference reference = (IASTReference) node;
|
||||
offset = reference.getOffset();
|
||||
length = reference.getName().length();
|
||||
if (VERBOSE)
|
||||
MatchLocator.verbose("Report Match: " + reference.getName());
|
||||
} else if( node instanceof IASTOffsetableNamedElement ){
|
||||
IASTOffsetableNamedElement offsetableElement = (IASTOffsetableNamedElement) node;
|
||||
offset = offsetableElement.getNameOffset() != 0 ? offsetableElement.getNameOffset()
|
||||
: offsetableElement.getStartingOffset();
|
||||
length = offsetableElement.getName().length();
|
||||
if (VERBOSE)
|
||||
MatchLocator.verbose("Report Match: " + offsetableElement.getName());
|
||||
}
|
||||
|
||||
|
||||
|
@ -438,5 +449,8 @@ public class MatchLocator implements ISourceElementRequestor, ICSearchConstants
|
|||
check( DECLARATIONS, elaboratedType );
|
||||
}
|
||||
|
||||
public static void verbose(String log) {
|
||||
System.out.println("(" + Thread.currentThread() + ") " + log);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,12 +18,18 @@ import org.eclipse.cdt.core.index.IndexModel;
|
|||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.parser.IScannerInfoProvider;
|
||||
import org.eclipse.cdt.core.resources.IConsole;
|
||||
import org.eclipse.cdt.core.search.SearchEngine;
|
||||
import org.eclipse.cdt.internal.core.CDescriptorManager;
|
||||
import org.eclipse.cdt.internal.core.CPathEntry;
|
||||
import org.eclipse.cdt.internal.core.model.BufferManager;
|
||||
import org.eclipse.cdt.internal.core.model.CModelManager;
|
||||
import org.eclipse.cdt.internal.core.model.IBufferFactory;
|
||||
import org.eclipse.cdt.internal.core.model.IWorkingCopy;
|
||||
import org.eclipse.cdt.internal.core.model.Util;
|
||||
import org.eclipse.cdt.internal.core.search.indexing.IndexManager;
|
||||
import org.eclipse.cdt.internal.core.search.indexing.SourceIndexer;
|
||||
import org.eclipse.cdt.internal.core.search.matching.MatchLocator;
|
||||
import org.eclipse.cdt.internal.core.sourcedependency.DependencyManager;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IProjectDescription;
|
||||
import org.eclipse.core.resources.IWorkspace;
|
||||
|
@ -38,6 +44,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
|
|||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
import org.eclipse.core.runtime.Preferences;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
|
@ -212,6 +219,9 @@ public class CCorePlugin extends Plugin {
|
|||
public void startup() throws CoreException {
|
||||
super.startup();
|
||||
|
||||
//Set debug tracing options
|
||||
CCorePlugin.getDefault().configurePluginDebugOptions();
|
||||
|
||||
// Fired up the model.
|
||||
fCoreModel = CoreModel.getDefault();
|
||||
fCoreModel.startup();
|
||||
|
@ -780,4 +790,40 @@ public class CCorePlugin extends Plugin {
|
|||
public static ICPathEntry newIncludeEntry(IPath path, IPath[] exclusionPatterns) {
|
||||
return new CPathEntry(ICPathEntry.CDT_INCLUDE, path, exclusionPatterns, null, null, null);
|
||||
}
|
||||
|
||||
private static final String MODEL = CCorePlugin.PLUGIN_ID + "/debug/model" ; //$NON-NLS-1$
|
||||
private static final String INDEXER = CCorePlugin.PLUGIN_ID + "/debug/indexer";
|
||||
private static final String INDEX_MANAGER = CCorePlugin.PLUGIN_ID + "/debug/indexmanager";
|
||||
private static final String SEARCH = CCorePlugin.PLUGIN_ID + "/debug/search" ; //$NON-NLS-1$
|
||||
private static final String MATCH_LOCATOR = CCorePlugin.PLUGIN_ID + "/debug/matchlocator" ; //$NON-NLS-1$
|
||||
private static final String PARSER = CCorePlugin.PLUGIN_ID + "/debug/parser" ; //$NON-NLS-1$
|
||||
private static final String DEPENDENCY = CCorePlugin.PLUGIN_ID + "/debug/dependency" ; //$NON-NLS-1$
|
||||
/**
|
||||
* Configure the plugin with respect to option settings defined in ".options" file
|
||||
*/
|
||||
public void configurePluginDebugOptions(){
|
||||
if(CCorePlugin.getDefault().isDebugging()){
|
||||
String option = Platform.getDebugOption(PARSER);
|
||||
if(option != null) Util.VERBOSE_PARSER = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
|
||||
|
||||
option = Platform.getDebugOption(MODEL);
|
||||
if(option != null) Util.VERBOSE_MODEL = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
|
||||
|
||||
option = Platform.getDebugOption(DEPENDENCY);
|
||||
if(option != null) DependencyManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
|
||||
|
||||
option = Platform.getDebugOption(INDEX_MANAGER);
|
||||
if(option != null) IndexManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
|
||||
|
||||
option = Platform.getDebugOption(INDEXER);
|
||||
if(option != null) SourceIndexer.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
|
||||
|
||||
option = Platform.getDebugOption(SEARCH);
|
||||
if(option != null) SearchEngine.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
|
||||
|
||||
option = Platform.getDebugOption(MATCH_LOCATOR);
|
||||
if(option != null) MatchLocator.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
2003-08-26 Bogdan Gheorghe
|
||||
- Converted CTags based OpenOnSelectionAction to OpenDeclarationsAction
|
||||
- Hooked up OpenDeclarationsAction to search engine
|
||||
|
||||
2003-08-20 Bogdan Gheorghe
|
||||
Added a search dialog pop up to the context menu for the
|
||||
CEditor and CContentOutlinePage
|
||||
|
|
|
@ -425,7 +425,7 @@ public class CEditor extends TextEditor implements ISelectionChangedListener {
|
|||
setAction("ContentAssistTip", action);
|
||||
|
||||
setAction("AddIncludeOnSelection", new AddIncludeOnSelectionAction(this)); //$NON-NLS-1$
|
||||
setAction("OpenOnSelection", new OpenOnSelectionAction(this));
|
||||
setAction("OpenDeclarations", new OpenDeclarationsAction(this));
|
||||
|
||||
fSearchForReferencesAction = new SearchForReferencesAction(getSelectionProvider());
|
||||
|
||||
|
@ -458,7 +458,7 @@ public class CEditor extends TextEditor implements ISelectionChangedListener {
|
|||
|
||||
addAction(menu, IContextMenuConstants.GROUP_GENERATE, "ContentAssistProposal"); //$NON-NLS-1$
|
||||
addAction(menu, IContextMenuConstants.GROUP_GENERATE, "AddIncludeOnSelection"); //$NON-NLS-1$
|
||||
addAction(menu, IContextMenuConstants.GROUP_GENERATE, "OpenOnSelection"); //$NON-NLS-1$
|
||||
addAction(menu, IContextMenuConstants.GROUP_GENERATE, "OpenDeclarations"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public void setOutlinePageInput(CContentOutlinePage page, IEditorInput input) {
|
||||
|
|
|
@ -65,11 +65,11 @@ OpenHierarchy.dialog.title=Open Type Hierarchy
|
|||
OpenHierarchy.label=Open Type &Hierarchy@F4
|
||||
OpenHierarchy.tooltip=Show the type hierarchy of the selected element
|
||||
|
||||
OpenOnSelection.description=Open an editor on the selected element
|
||||
OpenOnSelection.dialog.message=&Select or enter the element to open:
|
||||
OpenOnSelection.dialog.title=Open On Selection
|
||||
OpenOnSelection.label=&Open on Selection@F3
|
||||
OpenOnSelection.tooltip=Open an editor on the selected element
|
||||
OpenDeclarations.description=Open an editor on the selected element's declaration(s)
|
||||
OpenDeclarations.dialog.message=&Select or enter the element to open:
|
||||
OpenDeclarations.dialog.title=Open Declarations
|
||||
OpenDeclarations.label=&Open Declarations@F3
|
||||
OpenDeclarations.tooltip=Open an editor on the selected element's declaration(s)
|
||||
|
||||
OrganizeImports.description=Evaluate all required imports and replace the current imports
|
||||
OrganizeImports.error.message2=Syntax errors in compilation unit prevent correct evaluation\nof type references. Fix errors first.
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
/*
|
||||
* (c) Copyright IBM Corp. 2000, 2001.
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.search.BasicSearchResultCollector;
|
||||
import org.eclipse.cdt.core.search.ICSearchConstants;
|
||||
import org.eclipse.cdt.core.search.ICSearchScope;
|
||||
import org.eclipse.cdt.core.search.IMatch;
|
||||
import org.eclipse.cdt.core.search.SearchEngine;
|
||||
import org.eclipse.cdt.internal.core.search.matching.OrPattern;
|
||||
import org.eclipse.cdt.internal.ui.dialogs.ElementListSelectionDialog;
|
||||
import org.eclipse.cdt.internal.ui.util.EditorUtility;
|
||||
import org.eclipse.cdt.ui.CSearchResultLabelProvider;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.IWorkingCopyManager;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.jface.action.Action;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.ITextSelection;
|
||||
import org.eclipse.jface.window.Window;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.PartInitException;
|
||||
|
||||
/**
|
||||
* This action opens a java CEditor on the element represented by text selection of
|
||||
* the connected java source viewer.
|
||||
*
|
||||
* Use action from package org.eclipse.jdt.ui.actions
|
||||
*/
|
||||
public class OpenDeclarationsAction extends Action {
|
||||
|
||||
private String fDialogTitle;
|
||||
private String fDialogMessage;
|
||||
protected CEditor fEditor;
|
||||
BasicSearchResultCollector resultCollector = null;
|
||||
SearchEngine searchEngine = null;
|
||||
|
||||
/**
|
||||
* Creates a new action with the given label and image.
|
||||
*/
|
||||
protected OpenDeclarationsAction() {
|
||||
super();
|
||||
|
||||
setText(CEditorMessages.getString("OpenDeclarations.label")); //$NON-NLS-1$
|
||||
setToolTipText(CEditorMessages.getString("OpenDeclarations.tooltip")); //$NON-NLS-1$
|
||||
setDescription(CEditorMessages.getString("OpenDeclarations.description")); //$NON-NLS-1$
|
||||
setDialogTitle(CEditorMessages.getString("OpenDeclarations.dialog.title")); //$NON-NLS-1$
|
||||
setDialogMessage(CEditorMessages.getString("OpenDeclarations.dialog.message")); //$NON-NLS-1$
|
||||
|
||||
searchEngine = new SearchEngine();
|
||||
resultCollector = new BasicSearchResultCollector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action with the given image.
|
||||
*/
|
||||
public OpenDeclarationsAction(ImageDescriptor image) {
|
||||
this();
|
||||
setImageDescriptor(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action with the given editor
|
||||
*/
|
||||
public OpenDeclarationsAction(CEditor editor) {
|
||||
this();
|
||||
fEditor = editor;
|
||||
}
|
||||
|
||||
protected void setDialogTitle(String title) {
|
||||
fDialogTitle= title;
|
||||
}
|
||||
|
||||
protected void setDialogMessage(String message) {
|
||||
fDialogMessage= message;
|
||||
}
|
||||
|
||||
public void setContentEditor(CEditor editor) {
|
||||
fEditor= editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IAction#actionPerformed
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
IWorkingCopyManager fManager = CUIPlugin.getDefault().getWorkingCopyManager();
|
||||
ITranslationUnit unit = fManager.getWorkingCopy(fEditor.getEditorInput());
|
||||
|
||||
if (fEditor.getSelectionProvider() != null) {
|
||||
ITextSelection selection= (ITextSelection) fEditor.getSelectionProvider().getSelection();
|
||||
try {
|
||||
ArrayList elementsFound = new ArrayList();
|
||||
String sel = selection.getText();
|
||||
IFile file = fEditor.getInputFile();
|
||||
if(file == null)
|
||||
return;
|
||||
IProject project = file.getProject();
|
||||
if(project == null)
|
||||
return;
|
||||
|
||||
ICElement[] projectScopeElement = new ICElement[1];
|
||||
projectScopeElement[0] = unit.getCProject();//(ICElement)currentScope.getCProject();
|
||||
ICSearchScope scope = SearchEngine.createCSearchScope(projectScopeElement, true);
|
||||
OrPattern orPattern = new OrPattern();
|
||||
// search for global variables, functions, classes, structs, unions, enums and macros
|
||||
orPattern.addPattern(SearchEngine.createSearchPattern( sel, ICSearchConstants.VAR, ICSearchConstants.DECLARATIONS, true ));
|
||||
orPattern.addPattern(SearchEngine.createSearchPattern( sel, ICSearchConstants.FUNCTION, ICSearchConstants.DECLARATIONS, true ));
|
||||
orPattern.addPattern(SearchEngine.createSearchPattern( sel, ICSearchConstants.METHOD, ICSearchConstants.DECLARATIONS, true ));
|
||||
orPattern.addPattern(SearchEngine.createSearchPattern( sel, ICSearchConstants.TYPE, ICSearchConstants.DECLARATIONS, true ));
|
||||
orPattern.addPattern(SearchEngine.createSearchPattern( sel, ICSearchConstants.ENUM, ICSearchConstants.DECLARATIONS, true ));
|
||||
orPattern.addPattern(SearchEngine.createSearchPattern( sel, ICSearchConstants.FIELD, ICSearchConstants.DECLARATIONS, true ));
|
||||
orPattern.addPattern(SearchEngine.createSearchPattern( sel, ICSearchConstants.NAMESPACE, ICSearchConstants.DECLARATIONS, true ));
|
||||
orPattern.addPattern(SearchEngine.createSearchPattern( sel, ICSearchConstants.MACRO, ICSearchConstants.DECLARATIONS, true ));
|
||||
searchEngine.search(CUIPlugin.getWorkspace(), orPattern, scope, resultCollector);
|
||||
elementsFound.addAll(resultCollector.getSearchResults());
|
||||
|
||||
if (elementsFound.isEmpty() == false) {
|
||||
IMatch selected= selectCElement(elementsFound, getShell(), fDialogTitle, fDialogMessage);
|
||||
if (selected != null) {
|
||||
open(selected);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Exception x) {
|
||||
CUIPlugin.getDefault().log(x);
|
||||
}
|
||||
}
|
||||
|
||||
getShell().getDisplay().beep();
|
||||
}
|
||||
|
||||
protected Shell getShell() {
|
||||
return fEditor.getSite().getShell();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Opens the editor on the given element and subsequently selects it.
|
||||
*/
|
||||
protected void open(IMatch element) throws CModelException, PartInitException {
|
||||
IEditorPart part= EditorUtility.openInEditor(element.getResource());
|
||||
//int line = element.getStartOffset();
|
||||
//if(line > 0) line--;
|
||||
if(part instanceof CEditor) {
|
||||
CEditor ed = (CEditor)part;
|
||||
|
||||
try {
|
||||
IDocument document= ed.getDocumentProvider().getDocument(ed.getEditorInput());
|
||||
//if(line > 3) {
|
||||
// ed.selectAndReveal(document.getLineOffset(line - 3), 0);
|
||||
//}
|
||||
ed.selectAndReveal(element.getStartOffset() /*document.getLineOffset(line)*/, 0);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a dialog for resolving an ambigous C element.
|
||||
* Utility method that can be called by subclassers.
|
||||
*/
|
||||
protected IMatch selectCElement(List elements, Shell shell, String title, String message) {
|
||||
|
||||
int nResults= elements.size();
|
||||
|
||||
if (nResults == 0)
|
||||
return null;
|
||||
|
||||
if (nResults == 1)
|
||||
return (IMatch) elements.get(0);
|
||||
|
||||
|
||||
ElementListSelectionDialog dialog= new ElementListSelectionDialog(shell, new CSearchResultLabelProvider(), false, false);
|
||||
dialog.setTitle(title);
|
||||
dialog.setMessage(message);
|
||||
dialog.setElements(elements);
|
||||
|
||||
if (dialog.open() == Window.OK) {
|
||||
Object[] selection= dialog.getResult();
|
||||
if (selection != null && selection.length > 0) {
|
||||
nResults= selection.length;
|
||||
for (int i= 0; i < nResults; i++) {
|
||||
Object current= selection[i];
|
||||
if (current instanceof IMatch)
|
||||
return (IMatch) current;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
/*
|
||||
* (c) Copyright IBM Corp. 2000, 2001.
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
|
||||
import org.eclipse.cdt.core.index.ITagEntry;
|
||||
import org.eclipse.cdt.core.index.IndexModel;
|
||||
import org.eclipse.cdt.core.index.TagFlags;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.internal.ui.CPluginImages;
|
||||
import org.eclipse.cdt.internal.ui.dialogs.ElementListSelectionDialog;
|
||||
import org.eclipse.cdt.internal.ui.util.EditorUtility;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.jface.action.Action;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.ITextSelection;
|
||||
import org.eclipse.jface.viewers.LabelProvider;
|
||||
import org.eclipse.jface.window.Window;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.PartInitException;
|
||||
|
||||
|
||||
/**
|
||||
* This action opens a java editor on the element represented by text selection of
|
||||
* the connected java source viewer.
|
||||
*
|
||||
* Use action from package org.eclipse.jdt.ui.actions
|
||||
*/
|
||||
public class OpenOnSelectionAction extends Action {
|
||||
|
||||
private class TagEntryLabelProvider extends LabelProvider {
|
||||
|
||||
public TagEntryLabelProvider() {
|
||||
}
|
||||
|
||||
public Image getImage(Object element) {
|
||||
if(element instanceof ITagEntry) {
|
||||
int kind = ((ITagEntry)element).getKind();
|
||||
switch (kind) {
|
||||
case TagFlags.T_PROTOTYPE:
|
||||
return CPluginImages.get(CPluginImages.IMG_OBJS_DECLARATION);
|
||||
case TagFlags.T_CLASS:
|
||||
return CPluginImages.get(CPluginImages.IMG_OBJS_CLASS);
|
||||
case TagFlags.T_ENUM:
|
||||
case TagFlags.T_VARIABLE:
|
||||
case TagFlags.T_MEMBER:
|
||||
return CPluginImages.get(CPluginImages.IMG_OBJS_FIELD);
|
||||
case TagFlags.T_FUNCTION:
|
||||
return CPluginImages.get(CPluginImages.IMG_OBJS_FUNCTION);
|
||||
case TagFlags.T_STRUCT:
|
||||
return CPluginImages.get(CPluginImages.IMG_OBJS_STRUCT);
|
||||
case TagFlags.T_UNION:
|
||||
return CPluginImages.get(CPluginImages.IMG_OBJS_UNION);
|
||||
case TagFlags.T_MACRO:
|
||||
return CPluginImages.get(CPluginImages.IMG_OBJS_MACRO);
|
||||
}
|
||||
}
|
||||
return CPluginImages.get(CPluginImages.IMG_OBJS_FUNCTION);
|
||||
}
|
||||
|
||||
public String getText(Object element) {
|
||||
if(element instanceof ITagEntry) {
|
||||
ITagEntry entry = (ITagEntry) element;
|
||||
if(entry.getIFile() != null) {
|
||||
return entry.getIFile().getName() + ":" + entry.getTagName() + ":" + entry.getLineNumber() + " - " + entry.getIFile().getFullPath().toOSString();
|
||||
}
|
||||
return entry.getFileName() + ":" + entry.getTagName() + ":" + entry.getLineNumber();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private String fDialogTitle;
|
||||
private String fDialogMessage;
|
||||
protected CEditor fEditor;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new action with the given label and image.
|
||||
*/
|
||||
protected OpenOnSelectionAction() {
|
||||
super();
|
||||
|
||||
setText(CEditorMessages.getString("OpenOnSelection.label")); //$NON-NLS-1$
|
||||
setToolTipText(CEditorMessages.getString("OpenOnSelection.tooltip")); //$NON-NLS-1$
|
||||
setDescription(CEditorMessages.getString("OpenOnSelection.description")); //$NON-NLS-1$
|
||||
setDialogTitle(CEditorMessages.getString("OpenOnSelection.dialog.title")); //$NON-NLS-1$
|
||||
setDialogMessage(CEditorMessages.getString("OpenOnSelection.dialog.message")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action with the given image.
|
||||
*/
|
||||
public OpenOnSelectionAction(ImageDescriptor image) {
|
||||
this();
|
||||
setImageDescriptor(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action with the given editor
|
||||
*/
|
||||
public OpenOnSelectionAction(CEditor editor) {
|
||||
this();
|
||||
fEditor = editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new action without label. Initializing is
|
||||
* subclass responsibility.
|
||||
*/
|
||||
protected void OOpenOnSelectionAction(String label) {
|
||||
//this();
|
||||
//super(label);
|
||||
}
|
||||
|
||||
protected void setDialogTitle(String title) {
|
||||
fDialogTitle= title;
|
||||
}
|
||||
|
||||
protected void setDialogMessage(String message) {
|
||||
fDialogMessage= message;
|
||||
}
|
||||
|
||||
public void setContentEditor(CEditor editor) {
|
||||
fEditor= editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IAction#actionPerformed
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
IndexModel model = IndexModel.getDefault();
|
||||
if (model != null && fEditor.getSelectionProvider() != null) {
|
||||
ITextSelection selection= (ITextSelection) fEditor.getSelectionProvider().getSelection();
|
||||
try {
|
||||
String sel = selection.getText();
|
||||
IFile file = fEditor.getInputFile();
|
||||
if(file == null)
|
||||
return;
|
||||
IProject project = file.getProject();
|
||||
if(project == null)
|
||||
return;
|
||||
ITagEntry[] result= model.query(project,sel);
|
||||
|
||||
List filtered = new ArrayList();
|
||||
if (result != null && result.length > 0) {
|
||||
filterResolveResults(result, filtered);
|
||||
}
|
||||
|
||||
IProject[] p = project.getReferencedProjects();
|
||||
for ( int j= 0; j < p.length; j++ ) {
|
||||
result= model.query(p[j],sel);
|
||||
if (result != null && result.length > 0) {
|
||||
filterResolveResults(result, filtered);
|
||||
}
|
||||
}
|
||||
|
||||
if (filtered.isEmpty() == false) {
|
||||
ITagEntry selected= selectCElement(filtered, getShell(), fDialogTitle, fDialogMessage);
|
||||
if (selected != null) {
|
||||
open(selected);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (CModelException x) {
|
||||
CUIPlugin.getDefault().log(x.getStatus());
|
||||
} catch (PartInitException x) {
|
||||
CUIPlugin.getDefault().log(x);
|
||||
} catch (CoreException x) {
|
||||
CUIPlugin.getDefault().log(x);
|
||||
}
|
||||
}
|
||||
|
||||
getShell().getDisplay().beep();
|
||||
}
|
||||
|
||||
protected Shell getShell() {
|
||||
return fEditor.getSite().getShell();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Opens the editor on the given element and subsequently selects it.
|
||||
*/
|
||||
protected void open(ITagEntry element) throws CModelException, PartInitException {
|
||||
IEditorPart part= EditorUtility.openInEditor(element.getIFile());
|
||||
int line = element.getLineNumber();
|
||||
if(line > 0) line--;
|
||||
if(part instanceof CEditor) {
|
||||
CEditor ed = (CEditor)part;
|
||||
|
||||
try {
|
||||
IDocument document= ed.getDocumentProvider().getDocument(ed.getEditorInput());
|
||||
if(line > 3) {
|
||||
ed.selectAndReveal(document.getLineOffset(line - 3), 0);
|
||||
}
|
||||
ed.selectAndReveal(document.getLineOffset(line), 0);
|
||||
} catch (BadLocationException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out source references from the given code resolve results.
|
||||
* A utility method that can be called by subclassers.
|
||||
*/
|
||||
protected List filterResolveResults(ITagEntry[] codeResolveResults, List list) {
|
||||
int nResults= codeResolveResults.length;
|
||||
List refs= list;
|
||||
for (int i= 0; i < nResults; i++) {
|
||||
if (codeResolveResults[i].getKind() != TagFlags.T_PROTOTYPE) {
|
||||
refs.add(codeResolveResults[i]);
|
||||
}
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a dialog for resolving an ambigous C element.
|
||||
* Utility method that can be called by subclassers.
|
||||
*/
|
||||
protected ITagEntry selectCElement(List elements, Shell shell, String title, String message) {
|
||||
|
||||
int nResults= elements.size();
|
||||
|
||||
if (nResults == 0)
|
||||
return null;
|
||||
|
||||
if (nResults == 1)
|
||||
return (ITagEntry) elements.get(0);
|
||||
|
||||
//int flags= CElementLabelProvider.SHOW_DEFAULT
|
||||
// | CElementLabelProvider.SHOW_QUALIFIED
|
||||
// | CElementLabelProvider.SHOW_ROOT;
|
||||
|
||||
ElementListSelectionDialog dialog= new ElementListSelectionDialog(shell, new TagEntryLabelProvider(), false, false);
|
||||
dialog.setTitle(title);
|
||||
dialog.setMessage(message);
|
||||
dialog.setElements(elements);
|
||||
|
||||
if (dialog.open() == Window.OK) {
|
||||
Object[] selection= dialog.getResult();
|
||||
if (selection != null && selection.length > 0) {
|
||||
nResults= selection.length;
|
||||
for (int i= 0; i < nResults; i++) {
|
||||
Object current= selection[i];
|
||||
if (current instanceof ITagEntry)
|
||||
return (ITagEntry) current;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue