mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
Bug 337040 - MethodDefinitionInsertLocationFinder2 does not find implementation file when no definition already present. Patch by Marc-Andre Laperle.
This commit is contained in:
parent
29552b6bcf
commit
3715cdbbe8
8 changed files with 544 additions and 309 deletions
|
@ -26,11 +26,13 @@ import org.eclipse.cdt.core.model.ICProject;
|
|||
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
||||
import org.eclipse.cdt.core.testplugin.FileManager;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IWorkspace;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
|
||||
/**
|
||||
|
@ -42,13 +44,13 @@ abstract public class BaseTestFramework extends TestCase {
|
|||
static protected IProject project;
|
||||
static protected ICProject cproject;
|
||||
static protected FileManager fileManager;
|
||||
static protected boolean indexDisabled=false;
|
||||
|
||||
static protected boolean indexDisabled= false;
|
||||
|
||||
static void initProject() {
|
||||
if (project != null) {
|
||||
return;
|
||||
}
|
||||
if( CCorePlugin.getDefault() != null && CCorePlugin.getDefault().getCoreModel() != null){
|
||||
if (CCorePlugin.getDefault() != null && CCorePlugin.getDefault().getCoreModel() != null) {
|
||||
//(CCorePlugin.getDefault().getCoreModel().getIndexManager()).reset();
|
||||
monitor = new NullProgressMonitor();
|
||||
|
||||
|
@ -59,14 +61,11 @@ abstract public class BaseTestFramework extends TestCase {
|
|||
|
||||
project = cproject.getProject();
|
||||
|
||||
/*project.setSessionProperty(SourceIndexer.activationKey, Boolean.FALSE );
|
||||
/*project.setSessionProperty(SourceIndexer.activationKey, Boolean.FALSE);
|
||||
//Set the id of the source indexer extension point as a session property to allow
|
||||
//index manager to instantiate it
|
||||
project.setSessionProperty(IndexManager.indexerIDKey, sourceIndexerID);*/
|
||||
|
||||
|
||||
|
||||
} catch ( CoreException e ) {
|
||||
} catch (CoreException e) {
|
||||
/*boo*/
|
||||
}
|
||||
if (project == null)
|
||||
|
@ -77,22 +76,21 @@ abstract public class BaseTestFramework extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public BaseTestFramework()
|
||||
{
|
||||
public BaseTestFramework() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
*/
|
||||
public BaseTestFramework(String name)
|
||||
{
|
||||
public BaseTestFramework(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void cleanupProject() throws Exception {
|
||||
try{
|
||||
project.delete( true, false, monitor );
|
||||
} catch( Throwable e ){
|
||||
project.delete(true, false, monitor);
|
||||
} catch (Throwable e) {
|
||||
/*boo*/
|
||||
} finally {
|
||||
project= null;
|
||||
|
@ -106,36 +104,50 @@ abstract public class BaseTestFramework extends TestCase {
|
|||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
if( project == null || !project.exists() )
|
||||
if (project == null || !project.exists())
|
||||
return;
|
||||
|
||||
IResource [] members = project.members();
|
||||
for( int i = 0; i < members.length; i++ ){
|
||||
if( members[i].getName().equals( ".project" ) || members[i].getName().equals( ".cproject" ) ) //$NON-NLS-1$ //$NON-NLS-2$
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (members[i].getName().equals(".project") || members[i].getName().equals(".cproject")) //$NON-NLS-1$ //$NON-NLS-2$
|
||||
continue;
|
||||
if (members[i].getName().equals(".settings"))
|
||||
continue;
|
||||
try{
|
||||
members[i].delete( false, monitor );
|
||||
} catch( Throwable e ){
|
||||
try {
|
||||
members[i].delete(false, monitor);
|
||||
} catch (Throwable e) {
|
||||
/*boo*/
|
||||
}
|
||||
}
|
||||
}
|
||||
protected IFile importFile(String fileName, String contents ) throws Exception{
|
||||
//Obtain file handle
|
||||
|
||||
protected IFile importFile(String fileName, String contents) throws Exception {
|
||||
// Obtain file handle
|
||||
IFile file = project.getProject().getFile(fileName);
|
||||
|
||||
InputStream stream = new ByteArrayInputStream( contents.getBytes() );
|
||||
//Create file input stream
|
||||
if( file.exists() )
|
||||
file.setContents( stream, false, false, monitor );
|
||||
else
|
||||
file.create( stream, false, monitor );
|
||||
InputStream stream = new ByteArrayInputStream(contents.getBytes());
|
||||
// Create file input stream
|
||||
if (file.exists()) {
|
||||
file.setContents(stream, false, false, monitor);
|
||||
} else {
|
||||
IPath path = file.getLocation();
|
||||
path = path.makeRelativeTo(project.getLocation());
|
||||
if (path.segmentCount() > 1) {
|
||||
path = path.removeLastSegments(1);
|
||||
|
||||
for (int i = path.segmentCount() - 1; i >= 0; i--) {
|
||||
IPath currentPath = path.removeLastSegments(i);
|
||||
IFolder folder = project.getFolder(currentPath);
|
||||
if (!folder.exists()) {
|
||||
folder.create(false, true, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
file.create(stream, false, monitor);
|
||||
}
|
||||
|
||||
fileManager.addFile(file);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1458,6 +1458,7 @@ namespace foo
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
//=
|
||||
#include "Test.h"
|
||||
|
||||
|
@ -1478,3 +1479,103 @@ namespace foo
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
//!Bug 337040 - Insert definition in empty implementation file (.cxx)
|
||||
//#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest
|
||||
//@.config
|
||||
filename=Test.h
|
||||
getters=testField
|
||||
setters=testField
|
||||
|
||||
//@Test.h
|
||||
#ifndef TEST_H_
|
||||
#define TEST_H_
|
||||
|
||||
class Test
|
||||
{
|
||||
int /*$*/testField/*$$*/;
|
||||
};
|
||||
|
||||
#endif
|
||||
//=
|
||||
#ifndef TEST_H_
|
||||
#define TEST_H_
|
||||
|
||||
class Test
|
||||
{
|
||||
int testField;
|
||||
public:
|
||||
int getTestField() const;
|
||||
void setTestField(int testField);
|
||||
};
|
||||
|
||||
#endif
|
||||
//@Test.cxx
|
||||
|
||||
//=
|
||||
|
||||
|
||||
|
||||
int Test::getTestField() const
|
||||
{
|
||||
return testField;
|
||||
}
|
||||
|
||||
void Test::setTestField(int testField)
|
||||
{
|
||||
this->testField = testField;
|
||||
}
|
||||
|
||||
//!Bug 337040 - Insert definition in empty implementation file in complex directory structure
|
||||
//#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest
|
||||
//@.config
|
||||
filename=component_b/public_headers/Test.h
|
||||
getters=testField
|
||||
setters=testField
|
||||
|
||||
//@component_b/public_headers/Test.h
|
||||
#ifndef TEST_H_
|
||||
#define TEST_H_
|
||||
|
||||
class Test
|
||||
{
|
||||
int /*$*/testField/*$$*/;
|
||||
};
|
||||
|
||||
#endif
|
||||
//=
|
||||
#ifndef TEST_H_
|
||||
#define TEST_H_
|
||||
|
||||
class Test
|
||||
{
|
||||
int testField;
|
||||
public:
|
||||
int getTestField() const;
|
||||
void setTestField(int testField);
|
||||
};
|
||||
|
||||
#endif
|
||||
//@component_b/implementation/Test.cpp
|
||||
|
||||
//=
|
||||
|
||||
|
||||
|
||||
int Test::getTestField() const
|
||||
{
|
||||
return testField;
|
||||
}
|
||||
|
||||
void Test::setTestField(int testField)
|
||||
{
|
||||
this->testField = testField;
|
||||
}
|
||||
|
||||
//@component_a/public_headers/Test.h
|
||||
|
||||
//=
|
||||
|
||||
//@component_a/implementation/Test.cpp
|
||||
|
||||
//=
|
||||
|
|
|
@ -811,3 +811,25 @@ void n1::n2::A::B::testmethod2()
|
|||
|
||||
|
||||
|
||||
//!Bug 337040 - Insert definition in empty implementation file (.cxx)
|
||||
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
|
||||
//@.config
|
||||
filename=A.h
|
||||
//@A.h
|
||||
|
||||
class TestClass {
|
||||
public:
|
||||
/*$*/void foo();/*$$*/
|
||||
};
|
||||
|
||||
|
||||
//@A.cxx
|
||||
|
||||
//=
|
||||
|
||||
|
||||
|
||||
void TestClass::foo()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Anton Leherbauer (Wind River Systems) - initial API and implementation
|
||||
* Markus Schorn (Wind River Systems)
|
||||
* Marc-Andre Laperle - Extracted Util class from ToggleSourceHeaderAction
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IResourceProxy;
|
||||
import org.eclipse.core.resources.IResourceProxyVisitor;
|
||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.content.IContentType;
|
||||
import org.eclipse.core.runtime.content.IContentTypeManager;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.core.index.IIndexName;
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.model.ILanguage;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache;
|
||||
|
||||
/**
|
||||
* A collection of static methods for finding the source file corresponding to a header
|
||||
* and vice versa.
|
||||
*/
|
||||
public final class SourceHeaderPartnerFinder {
|
||||
|
||||
private static class Counter {
|
||||
public int fCount;
|
||||
}
|
||||
|
||||
private SourceHeaderPartnerFinder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the partner file for a translation unit.
|
||||
* The partner file is the corresponding source or header file
|
||||
* based on heuristics.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
private static class PartnerFileComputer implements ASTRunnable {
|
||||
PartnerFileVisitor fVisitor = null;
|
||||
|
||||
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) {
|
||||
if (ast != null && ast.getIndex() != null) {
|
||||
fVisitor = new PartnerFileVisitor();
|
||||
ast.accept(fVisitor);
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
|
||||
public IPath getPartnerFileLocation() {
|
||||
if(fVisitor != null) {
|
||||
return fVisitor.getPartnerFileLocation();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PartnerFileVisitor extends ASTVisitor {
|
||||
/**
|
||||
* When this many times the same partner file is hit,
|
||||
* we are confident enough to take it.
|
||||
*/
|
||||
private static final int CONFIDENCE_LIMIT = 15;
|
||||
/**
|
||||
* When this many times no match was found in the index,
|
||||
* we suspect that we won't get a good partner.
|
||||
*/
|
||||
private static final int SUSPECT_LIMIT = 15;
|
||||
|
||||
private IIndex fIndex;
|
||||
private IPath fFilePath;
|
||||
private Map<IPath, Counter> fMap;
|
||||
/** The confidence level == number of hits */
|
||||
private int fConfidence;
|
||||
/** Suspect level == number of no index matches */
|
||||
private int fSuspect;
|
||||
/** The current favorite partner file */
|
||||
private IPath fFavoriteLocation;
|
||||
|
||||
{
|
||||
shouldVisitDeclarators= true;
|
||||
shouldVisitTranslationUnit = true;
|
||||
}
|
||||
public PartnerFileVisitor() {
|
||||
fMap= new HashMap<IPath, Counter>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTTranslationUnit tu) {
|
||||
fIndex= tu.getIndex();
|
||||
if(fIndex == null) {
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
|
||||
fFilePath= Path.fromOSString(tu.getFilePath());
|
||||
return super.visit(tu);
|
||||
}
|
||||
|
||||
public IPath getPartnerFileLocation() {
|
||||
return fFavoriteLocation;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.core.dom.ast.ASTVisitor#visit(org.eclipse.cdt.core.dom.ast.IASTDeclarator)
|
||||
*/
|
||||
@Override
|
||||
public int visit(IASTDeclarator declarator) {
|
||||
if (declarator instanceof IASTFunctionDeclarator) {
|
||||
IASTName name= declarator.getName();
|
||||
if (name != null && declarator.getNestedDeclarator() == null) {
|
||||
IBinding binding= name.resolveBinding();
|
||||
if (binding != null && !(binding instanceof IProblemBinding)) {
|
||||
boolean isDefinition= name.isDefinition();
|
||||
final IIndexName[] partnerNames;
|
||||
try {
|
||||
if (isDefinition) {
|
||||
partnerNames= fIndex.findNames(binding,
|
||||
IIndex.FIND_DECLARATIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
|
||||
} else {
|
||||
partnerNames= fIndex.findNames(binding,
|
||||
IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
|
||||
}
|
||||
if (partnerNames.length == 0) {
|
||||
++fSuspect;
|
||||
if (fSuspect == SUSPECT_LIMIT) {
|
||||
fFavoriteLocation= null;
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
}
|
||||
for (int i= 0; i < partnerNames.length; i++) {
|
||||
IIndexName partnerName= partnerNames[i];
|
||||
IASTFileLocation partnerLocation= partnerName.getFileLocation();
|
||||
if (partnerLocation != null) {
|
||||
IPath partnerFileLocation= Path.fromOSString(partnerLocation.getFileName());
|
||||
if (!fFilePath.equals(partnerFileLocation)) {
|
||||
addPotentialPartnerFileLocation(partnerFileLocation);
|
||||
if (fConfidence == CONFIDENCE_LIMIT) {
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (CoreException exc) {
|
||||
CUIPlugin.log(exc.getStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
private void addPotentialPartnerFileLocation(IPath partnerFileLocation) {
|
||||
Counter counter= fMap.get(partnerFileLocation);
|
||||
if (counter == null) {
|
||||
counter= new Counter();
|
||||
fMap.put(partnerFileLocation, counter);
|
||||
}
|
||||
++counter.fCount;
|
||||
if (counter.fCount > fConfidence) {
|
||||
fConfidence= counter.fCount;
|
||||
fFavoriteLocation= partnerFileLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a file in the given resource container for the given basename.
|
||||
*
|
||||
* @param container
|
||||
* @param basename
|
||||
* @return a matching {@link IFile} or <code>null</code>, if no matching file was found
|
||||
*/
|
||||
private static IFile findInContainer(IContainer container, final String basename) {
|
||||
final IFile[] result= { null };
|
||||
IResourceProxyVisitor visitor= new IResourceProxyVisitor() {
|
||||
public boolean visit(IResourceProxy proxy) throws CoreException {
|
||||
if (result[0] != null) {
|
||||
return false;
|
||||
}
|
||||
if (!proxy.isAccessible()) {
|
||||
return false;
|
||||
}
|
||||
if (proxy.getType() == IResource.FILE && proxy.getName().equals(basename)) {
|
||||
result[0]= (IFile)proxy.requestResource();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}};
|
||||
try {
|
||||
container.accept(visitor, 0);
|
||||
} catch (CoreException exc) {
|
||||
// ignore
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
private static IContentType[] getPartnerContentTypes(String contentTypeId) {
|
||||
IContentTypeManager mgr= Platform.getContentTypeManager();
|
||||
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CHEADER)) {
|
||||
return new IContentType[] {
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CSOURCE),
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXSOURCE)
|
||||
};
|
||||
}
|
||||
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CSOURCE)) {
|
||||
return new IContentType[] {
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CHEADER),
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXHEADER)
|
||||
};
|
||||
}
|
||||
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CXXHEADER)) {
|
||||
return new IContentType[] {
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXSOURCE),
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CSOURCE)
|
||||
};
|
||||
}
|
||||
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CXXSOURCE)) {
|
||||
return new IContentType[] {
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXHEADER),
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CHEADER)
|
||||
};
|
||||
}
|
||||
return new IContentType[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a partner translation unit based on filename/extension matching.
|
||||
*
|
||||
* @param a partner translation unit or <code>null</code>
|
||||
*/
|
||||
private static ITranslationUnit getPartnerFileFromFilename(ITranslationUnit tu) {
|
||||
IPath sourceFileLocation= tu.getLocation();
|
||||
if (sourceFileLocation == null) {
|
||||
return null;
|
||||
}
|
||||
IPath partnerBasePath= sourceFileLocation.removeFileExtension();
|
||||
IContentType[] contentTypes= getPartnerContentTypes(tu.getContentTypeId());
|
||||
HashSet<String> extensionsTried= new HashSet<String>();
|
||||
for (int j = 0; j < contentTypes.length; j++) {
|
||||
IContentType contentType= contentTypes[j];
|
||||
String[] partnerExtensions;
|
||||
partnerExtensions= contentType.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
|
||||
for (int i= 0; i < partnerExtensions.length; i++) {
|
||||
String ext= partnerExtensions[i];
|
||||
if (extensionsTried.add(ext)) {
|
||||
String partnerFileBasename= partnerBasePath.addFileExtension(ext).lastSegment();
|
||||
|
||||
IFile partnerFile= null;
|
||||
IContainer container = tu.getResource().getParent();
|
||||
while (container != null && partnerFile == null && !(container instanceof IWorkspaceRoot)) {
|
||||
partnerFile= findInContainer(container, partnerFileBasename);
|
||||
container = container.getParent();
|
||||
}
|
||||
|
||||
if (partnerFile != null) {
|
||||
ITranslationUnit partnerUnit= (ITranslationUnit) CoreModel.getDefault().create(partnerFile);
|
||||
if (partnerUnit != null) {
|
||||
return partnerUnit;
|
||||
}
|
||||
}
|
||||
// External translation unit - try in same directory
|
||||
if (tu.getResource() == null) {
|
||||
IPath partnerFileLoation= partnerBasePath.removeLastSegments(1).append(partnerFileBasename);
|
||||
ITranslationUnit partnerUnit= CoreModel.getDefault().createTranslationUnitFrom(
|
||||
tu.getCProject(), partnerFileLoation);
|
||||
if (partnerUnit != null) {
|
||||
return partnerUnit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ITranslationUnit getPartnerTranslationUnit(ITranslationUnit tu) {
|
||||
ITranslationUnit partnerUnit= getPartnerFileFromFilename(tu);
|
||||
|
||||
if (partnerUnit == null) {
|
||||
// Search partner file based on definition/declaration association
|
||||
IProgressMonitor monitor= new NullProgressMonitor();
|
||||
PartnerFileComputer computer= new PartnerFileComputer();
|
||||
ASTProvider.getASTProvider().runOnAST(tu, ASTProvider.WAIT_ACTIVE_ONLY, monitor, computer);
|
||||
partnerUnit = createTranslationUnit(computer.getPartnerFileLocation(), tu.getCProject());
|
||||
}
|
||||
return partnerUnit;
|
||||
}
|
||||
|
||||
public static ITranslationUnit getPartnerTranslationUnit(ITranslationUnit tu,
|
||||
RefactoringASTCache astCache) throws CoreException {
|
||||
ITranslationUnit partnerUnit= getPartnerFileFromFilename(tu);
|
||||
|
||||
if (partnerUnit == null) {
|
||||
// Search partner file based on definition/declaration association
|
||||
IProgressMonitor monitor= new NullProgressMonitor();
|
||||
IASTTranslationUnit ast = astCache.getAST(tu, monitor);
|
||||
PartnerFileVisitor visitor = new PartnerFileVisitor();
|
||||
ast.accept(visitor);
|
||||
partnerUnit = createTranslationUnit(visitor.getPartnerFileLocation(), tu.getCProject());
|
||||
}
|
||||
return partnerUnit;
|
||||
}
|
||||
|
||||
private static ITranslationUnit createTranslationUnit(IPath partnerFileLoation, ICProject cProject) {
|
||||
ITranslationUnit partnerUnit = null;
|
||||
if (partnerFileLoation != null) {
|
||||
partnerUnit= (ITranslationUnit) CoreModel.getDefault().create(partnerFileLoation);
|
||||
if (partnerUnit == null) {
|
||||
partnerUnit= CoreModel.getDefault().createTranslationUnitFrom(cProject.getCProject(),
|
||||
partnerFileLoation);
|
||||
}
|
||||
}
|
||||
return partnerUnit;
|
||||
}
|
||||
}
|
|
@ -12,53 +12,20 @@
|
|||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IResourceProxy;
|
||||
import org.eclipse.core.resources.IResourceProxyVisitor;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.content.IContentType;
|
||||
import org.eclipse.core.runtime.content.IContentTypeManager;
|
||||
import org.eclipse.ui.IEditorInput;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.PartInitException;
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
import org.eclipse.ui.texteditor.TextEditorAction;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.core.index.IIndexName;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.model.ILanguage;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.model.IWorkingCopy;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.IWorkingCopyManager;
|
||||
|
||||
import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.util.EditorUtility;
|
||||
|
||||
/**
|
||||
|
@ -68,119 +35,6 @@ import org.eclipse.cdt.internal.ui.util.EditorUtility;
|
|||
*/
|
||||
public class ToggleSourceAndHeaderAction extends TextEditorAction {
|
||||
|
||||
private static class Counter {
|
||||
public int fCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the partner file for a translation unit.
|
||||
* The partner file is the corresponding source or header file
|
||||
* based on heuristics.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
private static class PartnerFileComputer extends ASTVisitor implements ASTRunnable {
|
||||
/**
|
||||
* When this many times the same partner file is hit,
|
||||
* we are confident enough to take it.
|
||||
*/
|
||||
private static final int CONFIDENCE_LIMIT = 15;
|
||||
/**
|
||||
* When this many times no match was found in the index,
|
||||
* we suspect that we won't get a good partner.
|
||||
*/
|
||||
private static final int SUSPECT_LIMIT = 15;
|
||||
|
||||
private IIndex fIndex;
|
||||
private IPath fFilePath;
|
||||
private Map<IPath, Counter> fMap;
|
||||
/** The confidence level == number of hits */
|
||||
private int fConfidence;
|
||||
/** Suspect level == number of no index matches */
|
||||
private int fSuspect;
|
||||
/** The current favorite partner file */
|
||||
private IPath fFavoriteLocation;
|
||||
|
||||
{
|
||||
shouldVisitDeclarators= true;
|
||||
}
|
||||
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) {
|
||||
if (ast != null) {
|
||||
fIndex= ast.getIndex();
|
||||
fFilePath= Path.fromOSString(ast.getFilePath());
|
||||
fMap= new HashMap<IPath, Counter>();
|
||||
if (fIndex != null) {
|
||||
ast.accept(this);
|
||||
}
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
|
||||
public IPath getPartnerFileLocation() {
|
||||
return fFavoriteLocation;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.core.dom.ast.ASTVisitor#visit(org.eclipse.cdt.core.dom.ast.IASTDeclarator)
|
||||
*/
|
||||
@Override
|
||||
public int visit(IASTDeclarator declarator) {
|
||||
if (declarator instanceof IASTFunctionDeclarator) {
|
||||
IASTName name= declarator.getName();
|
||||
if (name != null && declarator.getNestedDeclarator() == null) {
|
||||
IBinding binding= name.resolveBinding();
|
||||
if (binding != null && !(binding instanceof IProblemBinding)) {
|
||||
boolean isDefinition= name.isDefinition();
|
||||
final IIndexName[] partnerNames;
|
||||
try {
|
||||
if (isDefinition) {
|
||||
partnerNames= fIndex.findNames(binding, IIndex.FIND_DECLARATIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
|
||||
} else {
|
||||
partnerNames= fIndex.findNames(binding, IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
|
||||
}
|
||||
if (partnerNames.length == 0) {
|
||||
++fSuspect;
|
||||
if (fSuspect == SUSPECT_LIMIT) {
|
||||
fFavoriteLocation= null;
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
}
|
||||
for (int i= 0; i < partnerNames.length; i++) {
|
||||
IIndexName partnerName= partnerNames[i];
|
||||
IASTFileLocation partnerLocation= partnerName.getFileLocation();
|
||||
if (partnerLocation != null) {
|
||||
IPath partnerFileLocation= Path.fromOSString(partnerLocation.getFileName());
|
||||
if (!fFilePath.equals(partnerFileLocation)) {
|
||||
addPotentialPartnerFileLocation(partnerFileLocation);
|
||||
if (fConfidence == CONFIDENCE_LIMIT) {
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (CoreException exc) {
|
||||
CUIPlugin.log(exc.getStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
|
||||
private void addPotentialPartnerFileLocation(IPath partnerFileLocation) {
|
||||
Counter counter= fMap.get(partnerFileLocation);
|
||||
if (counter == null) {
|
||||
counter= new Counter();
|
||||
fMap.put(partnerFileLocation, counter);
|
||||
}
|
||||
++counter.fCount;
|
||||
if (counter.fCount > fConfidence) {
|
||||
fConfidence= counter.fCount;
|
||||
fFavoriteLocation= partnerFileLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ITranslationUnit fgLastPartnerUnit;
|
||||
private static ITranslationUnit fgLastSourceUnit;
|
||||
|
||||
|
@ -261,130 +115,6 @@ public class ToggleSourceAndHeaderAction extends TextEditorAction {
|
|||
}
|
||||
|
||||
// search partner file based on filename/extension
|
||||
ITranslationUnit partnerUnit= getPartnerFileFromFilename(tUnit);
|
||||
|
||||
if (partnerUnit == null) {
|
||||
// search partner file based on definition/declaration association
|
||||
IProgressMonitor monitor= new NullProgressMonitor();
|
||||
PartnerFileComputer computer= new PartnerFileComputer();
|
||||
ASTProvider.getASTProvider().runOnAST(tUnit, ASTProvider.WAIT_ACTIVE_ONLY, monitor, computer);
|
||||
IPath partnerFileLoation= computer.getPartnerFileLocation();
|
||||
if (partnerFileLoation != null) {
|
||||
partnerUnit= (ITranslationUnit) CoreModel.getDefault().create(partnerFileLoation);
|
||||
if (partnerUnit == null) {
|
||||
partnerUnit= CoreModel.getDefault().createTranslationUnitFrom(tUnit.getCProject(), partnerFileLoation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return partnerUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a partner translation unit based on filename/extension matching.
|
||||
*
|
||||
* @param a partner translation unit or <code>null</code>
|
||||
*/
|
||||
private ITranslationUnit getPartnerFileFromFilename(ITranslationUnit tUnit) {
|
||||
IPath sourceFileLocation= tUnit.getLocation();
|
||||
if (sourceFileLocation == null) {
|
||||
return null;
|
||||
}
|
||||
IPath partnerBasePath= sourceFileLocation.removeFileExtension();
|
||||
IContentType[] contentTypes= getPartnerContentTypes(tUnit.getContentTypeId());
|
||||
HashSet<String> extensionsTried= new HashSet<String>();
|
||||
for (int j = 0; j < contentTypes.length; j++) {
|
||||
IContentType contentType= contentTypes[j];
|
||||
String[] partnerExtensions;
|
||||
partnerExtensions= contentType.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
|
||||
for (int i= 0; i < partnerExtensions.length; i++) {
|
||||
String ext= partnerExtensions[i];
|
||||
if (extensionsTried.add(ext)) {
|
||||
String partnerFileBasename= partnerBasePath.addFileExtension(ext).lastSegment();
|
||||
|
||||
IFile partnerFile= null;
|
||||
if (tUnit.getResource() != null) {
|
||||
partnerFile= findInContainer(tUnit.getResource().getParent(), partnerFileBasename);
|
||||
}
|
||||
if (partnerFile == null) {
|
||||
partnerFile= findInContainer(tUnit.getCProject().getProject(), partnerFileBasename);
|
||||
}
|
||||
if (partnerFile != null) {
|
||||
ITranslationUnit partnerUnit= (ITranslationUnit) CoreModel.getDefault().create(partnerFile);
|
||||
if (partnerUnit != null) {
|
||||
return partnerUnit;
|
||||
}
|
||||
}
|
||||
// external tanslation unit - try in same directory
|
||||
if (tUnit.getResource() == null) {
|
||||
IPath partnerFileLoation= partnerBasePath.removeLastSegments(1).append(partnerFileBasename);
|
||||
ITranslationUnit partnerUnit= CoreModel.getDefault().createTranslationUnitFrom(tUnit.getCProject(), partnerFileLoation);
|
||||
if (partnerUnit != null) {
|
||||
return partnerUnit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a file in the given resource container for the given basename.
|
||||
*
|
||||
* @param container
|
||||
* @param basename
|
||||
* @return a matching {@link IFile} or <code>null</code>, if no matching file was found
|
||||
*/
|
||||
private IFile findInContainer(IContainer container, final String basename) {
|
||||
final IFile[] result= { null };
|
||||
IResourceProxyVisitor visitor= new IResourceProxyVisitor() {
|
||||
public boolean visit(IResourceProxy proxy) throws CoreException {
|
||||
if (result[0] != null) {
|
||||
return false;
|
||||
}
|
||||
if (!proxy.isAccessible()) {
|
||||
return false;
|
||||
}
|
||||
if (proxy.getType() == IResource.FILE && proxy.getName().equals(basename)) {
|
||||
result[0]= (IFile)proxy.requestResource();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}};
|
||||
try {
|
||||
container.accept(visitor, 0);
|
||||
} catch (CoreException exc) {
|
||||
// ignore
|
||||
}
|
||||
return result[0];
|
||||
}
|
||||
|
||||
private IContentType[] getPartnerContentTypes(String contentTypeId) {
|
||||
IContentTypeManager mgr= Platform.getContentTypeManager();
|
||||
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CHEADER)) {
|
||||
return new IContentType[] {
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CSOURCE),
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXSOURCE)
|
||||
};
|
||||
}
|
||||
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CSOURCE)) {
|
||||
return new IContentType[] {
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CHEADER),
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXHEADER)
|
||||
};
|
||||
}
|
||||
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CXXHEADER)) {
|
||||
return new IContentType[] {
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXSOURCE),
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CSOURCE)
|
||||
};
|
||||
}
|
||||
if (contentTypeId.equals(CCorePlugin.CONTENT_TYPE_CXXSOURCE)) {
|
||||
return new IContentType[] {
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CXXHEADER),
|
||||
mgr.getContentType(CCorePlugin.CONTENT_TYPE_CHEADER)
|
||||
};
|
||||
}
|
||||
return new IContentType[0];
|
||||
return SourceHeaderPartnerFinder.getPartnerTranslationUnit(tUnit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -272,7 +272,7 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring2 {
|
|||
|
||||
IASTSimpleDeclaration decl = context.existingFields.get(0);
|
||||
InsertLocation2 location = MethodDefinitionInsertLocationFinder2.find(
|
||||
decl.getFileLocation(), decl.getParent(), astCache);
|
||||
tu, decl.getFileLocation(), decl.getParent(), astCache);
|
||||
|
||||
if (location.getFile() == null || NodeHelper.isContainedInTemplateDeclaration(decl)) {
|
||||
location.setNodeToInsertAfter(NodeHelper.findTopLevelParent(decl), tu);
|
||||
|
|
|
@ -15,10 +15,9 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
||||
|
@ -27,7 +26,11 @@ import org.eclipse.cdt.core.dom.ast.IASTName;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
|
||||
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.SourceHeaderPartnerFinder;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.utils.DefinitionFinder;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.utils.FileHelper;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.utils.NodeHelper;
|
||||
|
@ -85,12 +88,15 @@ public class MethodDefinitionInsertLocationFinder {
|
|||
}
|
||||
}
|
||||
|
||||
IPath path = file.getLocation().removeFileExtension().addFileExtension("cpp"); //$NON-NLS-1$
|
||||
IFile fileForLocation = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);
|
||||
|
||||
if (fileForLocation != null && fileForLocation.exists()) {
|
||||
result.setInsertFile(fileForLocation);
|
||||
ITranslationUnit tu = (ITranslationUnit) CCorePlugin.getDefault().getCoreModel().create(file);
|
||||
ITranslationUnit partner = SourceHeaderPartnerFinder.getPartnerTranslationUnit(tu);
|
||||
if (partner != null) {
|
||||
IFile fileForLocation = ResourceLookup.selectFileForLocation(partner.getLocation(), file.getProject());
|
||||
if (fileForLocation != null && fileForLocation.exists()) {
|
||||
result.setInsertFile(fileForLocation);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@ import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.SourceHeaderPartnerFinder;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.utils.ASTNameInContext;
|
||||
import org.eclipse.cdt.internal.ui.refactoring.utils.DefinitionFinder2;
|
||||
|
@ -60,7 +62,7 @@ public class MethodDefinitionInsertLocationFinder2 {
|
|||
return functionDefinitionInParents;
|
||||
}
|
||||
|
||||
public static InsertLocation2 find(IASTFileLocation methodDeclarationLocation, IASTNode parent,
|
||||
public static InsertLocation2 find(ITranslationUnit declarationTu, IASTFileLocation methodDeclarationLocation, IASTNode parent,
|
||||
RefactoringASTCache astCache) throws CoreException {
|
||||
IASTDeclaration[] declarations = NodeHelper.getDeclarations(parent);
|
||||
InsertLocation2 insertLocation = new InsertLocation2();
|
||||
|
@ -82,6 +84,13 @@ public class MethodDefinitionInsertLocationFinder2 {
|
|||
definition.getName()), definition.getTranslationUnit());
|
||||
}
|
||||
}
|
||||
|
||||
if (insertLocation.getTranslationUnit() == null) {
|
||||
ITranslationUnit partner = SourceHeaderPartnerFinder.getPartnerTranslationUnit(declarationTu, astCache);
|
||||
if (partner != null) {
|
||||
insertLocation.setParentNode(astCache.getAST(partner, null), partner);
|
||||
}
|
||||
}
|
||||
|
||||
return insertLocation;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue