1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Merge remote-tracking branch 'cdt/master' into sd90

This commit is contained in:
Andrew Gvozdev 2011-12-08 16:40:00 -05:00
commit 0df3dfbbbc
55 changed files with 2627 additions and 679 deletions

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2010 IBM Corporation and others.
* Copyright (c) 2004, 2011 IBM Corporation 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
@ -58,7 +58,6 @@ public class DefaultRunSIProvider implements IExternalScannerInfoProvider {
private static final String EXTERNAL_SI_PROVIDER_ERROR = "ExternalScannerInfoProvider.Provider_Error"; //$NON-NLS-1$
private static final String GMAKE_ERROR_PARSER_ID = "org.eclipse.cdt.core.GmakeErrorParser"; //$NON-NLS-1$
private static final String PREF_CONSOLE_ENABLED = "org.eclipse.cdt.make.core.scanner.discovery.console.enabled"; //$NON-NLS-1$
private static final String LANG_ENV_VAR = "LANG"; //$NON-NLS-1$
private static final String NEWLINE = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
private static final String PATH_ENV = "PATH"; //$NON-NLS-1$
@ -269,14 +268,12 @@ public class DefaultRunSIProvider implements IExternalScannerInfoProvider {
props.put("PWD", fWorkingDirectory.toOSString()); //$NON-NLS-1$
}
// On POSIX (Linux, UNIX) systems reset LANG variable to English with
// UTF-8 encoding
// since GNU compilers can handle only UTF-8 characters. English language is chosen
// beacuse GNU compilers inconsistently handle different locales when generating
// output of the 'gcc -v' command. Include paths with locale characters will be
// handled properly regardless of the language as long as the encoding is set to UTF-8.
if (props.containsKey(LANG_ENV_VAR)) {
props.put(LANG_ENV_VAR, "en_US.UTF-8"); //$NON-NLS-1$
}
// UTF-8 encoding since GNU compilers can handle only UTF-8 characters.
// Include paths with locale characters will be handled properly regardless
// of the language as long as the encoding is set to UTF-8.
// English language is chosen because parser relies on English messages
// in the output of the 'gcc -v' command.
props.put("LC_ALL", "en_US.UTF-8"); //$NON-NLS-1$ //$NON-NLS-2$
return props;
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2010 IBM Corporation and others.
* Copyright (c) 2004, 2011 IBM Corporation 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
@ -26,7 +26,6 @@ import org.eclipse.core.runtime.CoreException;
* @author vhirsl
*/
public class GCCSpecsRunSIProvider extends DefaultRunSIProvider {
/* (non-Javadoc)
* @see org.eclipse.cdt.make.internal.core.scannerconfig2.DefaultRunSIProvider#initialize()
*/

View file

@ -338,9 +338,9 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild
if (parentConfig != null) {
name = parentConfig.getName();
// If this contructor is called to clone an existing
// If this constructor is called to clone an existing
// configuration, the parent of the parent should be stored.
// As of 2.1, there is still one single level of inheritence to
// As of 2.1, there is still one single level of inheritance to
// worry about
parent = parentConfig.getParent() == null ? parentConfig : parentConfig.getParent();
}
@ -486,7 +486,7 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild
// if(!baseCfg.isExtensionConfig)
// cloneChildren = true;
// If this contructor is called to clone an existing
// If this constructor is called to clone an existing
// configuration, the parent of the cloning config should be stored.
parent = baseCfg.isExtensionConfig || baseCfg.getParent() == null ? baseCfg : baseCfg.getParent();
@ -634,7 +634,7 @@ public class Configuration extends BuildObject implements IConfiguration, IBuild
if(!cloneConfig.isExtensionConfig)
cloneChildren = true;
// If this contructor is called to clone an existing
// If this constructor is called to clone an existing
// configuration, the parent of the cloning config should be stored.
parent = cloneConfig.isExtensionConfig || cloneConfig.getParent() == null ? cloneConfig : cloneConfig.getParent();
parentId = parent.getId();

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2005, 2010 Intel Corporation and others.
* Copyright (c) 2005, 2011 Intel Corporation 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
@ -23,10 +23,15 @@ import org.eclipse.cdt.managedbuilder.internal.envvar.BuildEnvVar;
public class GnuCygwinConfigurationEnvironmentSupplier implements
IConfigurationEnvironmentVariableSupplier {
static final String VARNAME = "PATH"; //$NON-NLS-1$
static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$
static final String PROPERTY_DELIMITER = "path.separator"; //$NON-NLS-1$
static final String PROPERTY_OSNAME = "os.name"; //$NON-NLS-1$
private static final String PATH = "PATH"; //$NON-NLS-1$
private static final String DELIMITER_UNIX = ":"; //$NON-NLS-1$
private static final String PROPERTY_DELIMITER = "path.separator"; //$NON-NLS-1$
private static final String PROPERTY_OSNAME = "os.name"; //$NON-NLS-1$
private static final String LANG = "LANG"; //$NON-NLS-1$
private static final String LC_ALL = "LC_ALL"; //$NON-NLS-1$
private static final String LC_MESSAGES = "LC_MESSAGES"; //$NON-NLS-1$
/* (non-Javadoc)
* @see org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier#getVariable(java.lang.String, org.eclipse.cdt.managedbuilder.core.IConfiguration, org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider)
*/
@ -34,15 +39,33 @@ public class GnuCygwinConfigurationEnvironmentSupplier implements
public IBuildEnvironmentVariable getVariable(String variableName,
IConfiguration configuration, IEnvironmentVariableProvider provider) {
if (variableName == null)
return null;
if (!System.getProperty(PROPERTY_OSNAME).toLowerCase().startsWith("windows ")) //$NON-NLS-1$
return null;
if (variableName == null) return null;
if (!VARNAME.equalsIgnoreCase(variableName)) return null;
if (variableName.equalsIgnoreCase(PATH)) {
String p = CygwinPathResolver.getBinPath();
if (p != null)
return new BuildEnvVar(VARNAME, p.replace('/','\\'), IBuildEnvironmentVariable.ENVVAR_PREPEND, System.getProperty(PROPERTY_DELIMITER, DELIMITER_UNIX));
return new BuildEnvVar(PATH, p.replace('/','\\'), IBuildEnvironmentVariable.ENVVAR_PREPEND, System.getProperty(PROPERTY_DELIMITER, DELIMITER_UNIX));
} else if (variableName.equalsIgnoreCase(LANG)) {
// Workaround for not being able to select encoding for CDT console -> change codeset to Latin1
String langValue = System.getenv(LANG);
if (langValue == null || langValue.length() == 0)
langValue = System.getenv(LC_ALL);
if (langValue == null || langValue.length() == 0)
langValue = System.getenv(LC_MESSAGES);
if (langValue != null && langValue.length() > 0)
// langValue is [language[_territory][.codeset][@modifier]], i.e. "en_US.UTF-8@dict"
// we replace codeset with Latin1 as CDT console garbles UTF
// and ignore modifier which is not used by LANG
langValue = langValue.replaceFirst("([^.@]*)(\\..*)?(@.*)?", "$1.ISO-8859-1"); //$NON-NLS-1$ //$NON-NLS-2$
else
langValue = "C.ISO-8859-1"; //$NON-NLS-1$
return new BuildEnvVar(LANG, langValue);
}
return null;
}
@ -53,9 +76,13 @@ public class GnuCygwinConfigurationEnvironmentSupplier implements
public IBuildEnvironmentVariable[] getVariables(
IConfiguration configuration, IEnvironmentVariableProvider provider) {
IBuildEnvironmentVariable[] tmp = new IBuildEnvironmentVariable[1];
tmp[0] = getVariable(VARNAME, configuration, provider);
if (tmp[0] != null) return tmp;
return null;
IBuildEnvironmentVariable varLang = getVariable(LANG, configuration, provider);
IBuildEnvironmentVariable varPath = getVariable(PATH, configuration, provider);
if (varPath != null) {
return new IBuildEnvironmentVariable[] {varLang, varPath};
} else {
return new IBuildEnvironmentVariable[] {varLang};
}
}
}

View file

@ -98,8 +98,8 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker {
public int visit(IASTExpression expression) {
if (!constructorsStack.empty() && expression instanceof IASTFunctionCallExpression) {
Set<IField> actualContructorFields = constructorsStack.peek();
if (!actualContructorFields.isEmpty()) {
Set<IField> actualConstructorFields = constructorsStack.peek();
if (!actualConstructorFields.isEmpty()) {
boolean skipCurrentConstructor = false;
IASTFunctionCallExpression fCall = (IASTFunctionCallExpression)expression;
IASTExpression fNameExp = fCall.getFunctionNameExpression();
@ -108,7 +108,7 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker {
IBinding fBinding = fName.getName().resolveBinding();
if (fBinding instanceof ICPPMethod) {
ICPPMethod method = (ICPPMethod)fBinding;
ICompositeType constructorOwner = actualContructorFields.iterator().next().getCompositeTypeOwner();
ICompositeType constructorOwner = actualConstructorFields.iterator().next().getCompositeTypeOwner();
if (constructorOwner == method.getClassOwner() && !method.getType().isConst()) {
skipCurrentConstructor = true;
}
@ -152,12 +152,12 @@ public class ClassMembersInitializationChecker extends AbstractIndexAstChecker {
public int visit(IASTName name) {
if (!constructorsStack.empty()) {
Set<IField> actualContructorFields = constructorsStack.peek();
if (!actualContructorFields.isEmpty()) {
Set<IField> actualConstructorFields = constructorsStack.peek();
if (!actualConstructorFields.isEmpty()) {
IBinding binding = name.resolveBinding();
if (actualContructorFields.contains(binding)) {
if (actualConstructorFields.contains(binding)) {
if ((CPPVariableReadWriteFlags.getReadWriteFlags(name) & PDOMName.WRITE_ACCESS) != 0) {
actualContructorFields.remove(binding);
actualConstructorFields.remove(binding);
}
}
}

View file

@ -53,7 +53,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
// int m;
// C() { m = 0; } // No warnings.
// };
public void testAssignmentsInContructorShouldBeChecked() {
public void testAssignmentsInConstructorShouldBeChecked() {
loadCodeAndRun(getAboveComment());
checkNoErrors();
}
@ -171,7 +171,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
// int i1, i2;
// };
// C::C() : i1(0) {} // 1 warning for: i2.
public void testExternalContructorHandling() {
public void testExternalConstructorHandling() {
loadCodeAndRun(getAboveComment());
checkErrorLines(5);
}
@ -184,7 +184,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
// T2 t2;
// };
// C::C() : i1(0), t1(T1()) {} // 1 warning for: i2.
public void testExternalContructorOfTemplateClassHandling() {
public void testExternalConstructorOfTemplateClassHandling() {
loadCodeAndRun(getAboveComment());
checkErrorLines(8);
}
@ -196,7 +196,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
// };
// template <typename T>
// C::C() : i1(0) {} // 1 warning for: i2.
public void testExternalTemplateContructorHandling() {
public void testExternalTemplateConstructorHandling() {
loadCodeAndRun(getAboveComment());
checkErrorLines(7);
}
@ -212,7 +212,7 @@ public class ClassMembersInitializationCheckerTest extends CheckerTestCase {
// template <typename T1, typename T2>
// template <typename T>
// C<T1,T2>::C() : i1(0), t1(T1()) {} // 1 warning for: i2.
public void testExternalTemplateContructorOfTemplateClassHandling() {
public void testExternalTemplateConstructorOfTemplateClassHandling() {
loadCodeAndRun(getAboveComment());
checkErrorLines(11);
}

View file

@ -122,7 +122,7 @@ public class ReturnCheckerTest extends CheckerTestCase {
// return;
// }
// };
public void testContructorRetValue() {
public void testConstructorRetValue() {
loadCodeAndRunCpp(getAboveComment());
checkErrorLine(3, ReturnChecker.RET_ERR_VALUE_ID);
}
@ -136,7 +136,7 @@ public class ReturnCheckerTest extends CheckerTestCase {
// return;
// }
// };
public void testContructor_Bug323602() {
public void testConstructor_Bug323602() {
IProblemPreference macro = getPreference(ReturnChecker.RET_NO_VALUE_ID, ReturnChecker.PARAM_IMPLICIT);
macro.setValue(Boolean.TRUE);
loadCodeAndRunCpp(getAboveComment());

View file

@ -86,7 +86,7 @@ ptym_open(char * pts_name)
char *ptr;
strcpy(pts_name, "/dev/ptmx");
fdm = getpt();
fdm = posix_openpt(O_RDWR);
if (fdm < 0)
return -1;
if (grantpt(fdm) < 0) { /* grant access to slave */

View file

@ -1942,16 +1942,17 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest {
}
// void f(double& a) { a += 3.14; }
// // ...
// int foo() {
// void foo1() {
// double d = 0;
// f(d);
// }
//
// int v[20];
// // ...
// int& g(int i) { return v[i]; }
// // ...
// void foo2() {
// g(3) = 7;
// }
//
// struct link {
// link* next;
// };
@ -1967,7 +1968,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest {
// link* q = new link;
// h(q);
// }
public void test8_3_2s2() throws Exception {
public void test8_3_2s3() throws Exception {
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
}

View file

@ -6393,6 +6393,24 @@ public class AST2CPPTests extends AST2BaseTest {
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(8).resolveBinding());
}
// template <typename T> class A;
// template <template<typename> class T> class A {};
// template <template<typename> class T> class A;
// template <template<typename> class T> class B {};
// template <typename T> class B;
// template <typename T> class B {};
public void testInvalidClassRedeclaration_364226() throws Exception {
final String code = getAboveComment();
IASTTranslationUnit tu= parse(code, ParserLanguage.CPP, true, false);
CPPNameCollector nc= new CPPNameCollector();
tu.accept(nc);
assertProblemBindings(nc, 4);
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(4).resolveBinding());
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(7).resolveBinding());
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(12).resolveBinding());
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(14).resolveBinding());
}
// struct Foo {
// void foo();
// };

View file

@ -5583,4 +5583,59 @@ public class AST2TemplateTests extends AST2BaseTest {
public void testDirectlyNestedAmbiguity_362976() throws Exception {
parseAndCheckBindings();
}
// template<typename T, T p1, T p2, T p3=T(), T p4=T(), T p5=T(),
// T p6=T(), T p7=T(), T p8=T(), T p9=T(), T p10=T(),
// T p11=T(), T p12=T(), T p13=T(), T p14=T(), T p15=T(),
// T p16=T(), T p17=T(), T p18=T(), T p19=T(), T p20=T()
// >
// struct MaxOfN {
// template<typename X, X x1, X x2> struct Max2 {
// static const X result = (x1>x2)?x1:x2;
// };
// static const T result = Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,
// (Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,p1,p2>::result),
// p3>::result),p4>::result),p5>::result),p6>::result),p7>::result),p8>::result),
// p9>::result),p10>::result),p11>::result),p12>::result),p13>::result),p14>::result),
// p15>::result),p16>::result),p17>::result),p18>::result),p19>::result),p20>::result;
// };
// int main(){
// return MaxOfN<int,1,2>::result;
// }
public void testNestedTemplateAmbiguity_363609() throws Exception {
parseAndCheckBindings();
}
// struct A {
// void m() {}
// };
// template <class T, void (T::*m)() = &T::m> struct B {};
// void test() {
// B<A> b1;
// }
public void testDefaultArgForNonTypeTemplateParameter_363743() throws Exception {
parseAndCheckBindings();
}
// template<class T> struct A {
// bool b;
// };
// class B {
// };
// template<class T> T * func();
// void test1() {
// delete func<A<B>>(); // This line causes the NPE
// }
//
// template<bool> struct C {
// int* ptr;
// };
// void test2() {
// int a = 0, b = 1;
// delete C< a<b >::ptr;
// delete C< A<B>::b >::ptr;
// }
public void testTemplateAmbiguityInDeleteExpression_364225() throws Exception {
parseAndCheckBindings();
}
}

View file

@ -14,7 +14,9 @@ import java.io.IOException;
import junit.framework.TestSuite;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.parser.util.ASTPrinter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.parser.ParserException;
@ -39,6 +41,13 @@ public class ClassTypeHelperTests extends AST2BaseTest {
return new BindingAssertionHelper(code, true);
}
// int a;
// const int& b;
public void testTemp() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ASTPrinter.print(helper.getTranslationUnit());
}
// struct A {
// A(const A& a);
// };

View file

@ -278,4 +278,41 @@ public class FaultToleranceTests extends AST2BaseTest {
p= getDeclaration(tu, 1);
s= getDeclaration(tu, 2);
}
// TINT* f(TINT* p) {
// TINT* f1(TINT* p) {
// TINT* f2(TINT* p) {
// TINT* f3(TINT* p) {
// TINT* f4(TINT* p) {
// TINT* f5(TINT* p) {
// TINT* f6(TINT* p) {
// TINT* f7(TINT* p) {
// TINT* f8(TINT* p) {
// TINT* f9(TINT* p) {
// TINT* f10(TINT* p) {
// TINT* f11(TINT* p) {
// TINT* f12(TINT* p) {
// TINT* f13(TINT* p) {
// TINT* f14(TINT* p) {
// TINT* f15(TINT* p) {
// TINT* f16(TINT* p) {
// TINT* f17(TINT* p) {
// TINT* f18(TINT* p) {
// TINT* f19(TINT* p) {
// TINT* f20(TINT* p) {
// TINT* f21(TINT* p) {
// TINT* f22(TINT* p) {
// TINT* f23(TINT* p) {
// TINT* f24(TINT* p) {
// TINT* f25(TINT* p) {
// TINT* f26(TINT* p) {
// TINT* f27(TINT* p) {
// TINT* f28(TINT* p) {
// TINT* f29(TINT* p) {
// }
public void testPerformanceIssue_364108() throws Exception {
final String comment= getAboveComment();
parse(comment, ParserLanguage.CPP, false, false);
parse(comment, ParserLanguage.C, false, false);
}
}

View file

@ -216,7 +216,7 @@ public class GCCCompleteParseExtensionsTest extends AST2BaseTest {
parseGPP( writer.toString() );
writer = new StringWriter();
writer.write( "int x = ({ int foo() { return 1; } int y = foo (); int z;\n" ); //$NON-NLS-1$
writer.write( "int x = ({ int foo(); int y = foo (); int z;\n" ); //$NON-NLS-1$
writer.write( "if (y > 0) z = y;\n" ); //$NON-NLS-1$
writer.write( "else z = - y;\n" );//$NON-NLS-1$
writer.write( "z; });\n" );//$NON-NLS-1$

View file

@ -288,6 +288,42 @@ public class IndexNamesTests extends BaseTestCase {
}
}
// class A {
// virtual void foo(){}
// template<typename C> void SetCallback(C callback){}
// void InitCallback() {
// SetCallback(&A::foo); // Can be A::foo or B::foo
// }
// };
// class B: public A {
// virtual void foo(){}
// };
public void testAddressOfPolymorphicMethod_Bug363731() throws Exception {
waitForIndexer();
String content= getComment();
IFile file= createFile(getProject().getProject(), "test.cpp", content);
waitUntilFileIsIndexed(file, 4000);
fIndex.acquireReadLock();
try {
IIndexFile ifile= getIndexFile(ILinkage.CPP_LINKAGE_ID, file);
IIndexName[] names= ifile.findNames(0, content.length());
int j= 0;
for (IIndexName indexName : names) {
if (indexName.isReference() && indexName.toString().equals("foo")) {
assertEquals(true, indexName.couldBePolymorphicMethodCall());
assertEquals("A", CPPVisitor.getQualifiedName(fIndex.findBinding(indexName))[0]);
j++;
} else {
assertEquals(false, indexName.couldBePolymorphicMethodCall());
}
}
assertEquals(1, j);
} finally {
fIndex.releaseReadLock();
}
}
// int _i, ri, wi, rwi;
// int* rp; int* wp; int* rwp;
// const int* cip= &ri;

View file

@ -17,11 +17,10 @@ package org.eclipse.cdt.core.dom.ast;
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface IASTDeclarator extends IASTNode, IASTNameOwner {
/**
* Constant - empty declarator array
*/
public static final IASTDeclarator[] EMPTY_DECLARATOR_ARRAY = new IASTDeclarator[0];
public static final IASTDeclarator[] EMPTY_DECLARATOR_ARRAY = {};
/**
* <code>POINTER_OPERATOR</code> represents the relationship between an
@ -111,10 +110,12 @@ public interface IASTDeclarator extends IASTNode, IASTNameOwner {
/**
* @since 5.1
*/
@Override
public IASTDeclarator copy();
/**
* @since 5.3
*/
@Override
public IASTDeclarator copy(CopyStyle style);
}

View file

@ -15,19 +15,20 @@ package org.eclipse.cdt.core.dom.ast;
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface IASTPointerOperator extends IASTNode {
/**
* Constant/sentinel.
*/
public static final IASTPointerOperator[] EMPTY_ARRAY = new IASTPointerOperator[0];
public static final IASTPointerOperator[] EMPTY_ARRAY = {};
/**
* @since 5.1
*/
@Override
public IASTPointerOperator copy();
/**
* @since 5.3
*/
@Override
public IASTPointerOperator copy(CopyStyle style);
}

View file

@ -20,7 +20,6 @@ import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPASTReferenceOperator extends IASTPointerOperator {
/**
* Returns whether the operator denotes a rvalue reference (e.g. <code>int &&</code>).
* @since 5.2
@ -30,10 +29,12 @@ public interface ICPPASTReferenceOperator extends IASTPointerOperator {
/**
* @since 5.1
*/
@Override
public ICPPASTReferenceOperator copy();
/**
* @since 5.3
*/
@Override
public ICPPASTReferenceOperator copy(CopyStyle style);
}

View file

@ -52,10 +52,9 @@ public class TypeHelper {
}
SizeofCalculator calc = ((ASTTranslationUnit) ast).getSizeofCalculator();
SizeAndAlignment sizeofPointer = calc.sizeAndAlignmentOfPointer();
if (sizeofPointer == null)
return true;
long maxSize = sizeofPointer != null ? sizeofPointer.size : 4;
SizeAndAlignment sizeofType = calc.sizeAndAlignment(type);
if (sizeofType == null || sizeofType.size > sizeofPointer.size)
if (sizeofType == null || sizeofType.size > maxSize)
return true;
}
return false;

View file

@ -90,6 +90,7 @@ import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
*/
public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
public interface ITemplateIdStrategy {
boolean shallParseAsTemplateID(IASTName name);
}
protected static class FoundAggregateInitializer extends Exception {
@ -243,6 +244,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
throw backtrack;
}
@Override
public IASTCompletionNode getCompletionNode() {
return completionNode;
}
@ -555,6 +557,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
parsePassed = false;
}
@Override
public synchronized void cancel() {
isCancelled = true;
}
@ -642,6 +645,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
throwBacktrack(n.getOffset(), n.getLength());
}
@Override
public IASTTranslationUnit parse() {
long startTime = System.currentTimeMillis();
translationUnit();
@ -1173,22 +1177,27 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return fUnaryOperatorOffset;
}
@Override
public IASTExpression copy() {
throw new UnsupportedOperationException();
}
@Override
public IASTExpression copy(CopyStyle style) {
throw new UnsupportedOperationException();
}
@Override
public IType getExpressionType() {
throw new UnsupportedOperationException();
}
@Override
public boolean isLValue() {
throw new UnsupportedOperationException();
}
@Override
public ValueCategory getValueCategory() {
throw new UnsupportedOperationException();
}
@ -1198,12 +1207,15 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (LT(1) == IToken.tLPAREN) {
final IToken mark= mark();
final int startingOffset= mark.getOffset();
final boolean canBeCast= canBeCastExpression();
consume();
IASTTypeId typeId= null;
if (canBeCast) {
try {
typeId= typeId(DeclarationOptions.TYPEID);
} catch (BacktrackException e) {
}
}
if (typeId != null && LT(1) == IToken.tRPAREN) {
consume();
boolean unaryFailed= false;
@ -1562,6 +1574,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return skipProblemConditionInParenthesis(mark.getOffset());
}
@Override
public boolean encounteredError() {
return !parsePassed;
}
@ -1862,9 +1875,11 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
ds = nodeFactory.newDeclarationStatement(d);
setRange(ds, d);
} catch (BacktrackException b) {
if (expressionStatement == null) {
IASTNode node = b.getNodeBeforeProblem();
if (node instanceof IASTDeclaration) {
final boolean isProblemDecl = node instanceof IASTDeclaration;
if (expressionStatement == null
|| (!foundSemicolon && isProblemDecl && node.contains(expressionStatement))) {
if (isProblemDecl) {
ds= nodeFactory.newDeclarationStatement((IASTDeclaration) node);
b.initialize(b.getProblem(), setRange(ds, node));
}
@ -2399,7 +2414,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (token.getType() == IGCCToken.t__declspec) {
consume();
if (LT(1) == IToken.tLPAREN) {
skipBrackets(IToken.tLPAREN, IToken.tRPAREN);
skipBrackets(IToken.tLPAREN, IToken.tRPAREN, 0);
}
}
}
@ -2433,24 +2448,68 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
}
/**
* In case a cast expression is followed by +/- or & we should avoid it:
* (a)+1 vs. (int)+1;
* @since 4.0
*/
protected boolean avoidCastExpressionByHeuristics() throws EndOfFileException {
if (LT(1) == IToken.tIDENTIFIER) {
if (LT(2) == IToken.tRPAREN) {
switch (LT(3)) {
case IToken.tPLUS:
case IToken.tMINUS:
case IToken.tAMPER:
case IToken.tSTAR:
return true;
}
}
}
protected boolean canBeCompoundLiteral() throws EndOfFileException {
IToken m= mark();
try {
// The parenthesis cannot be followed by a binary operator
skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI);
return LTcatchEOF(1) == IToken.tLBRACE;
} catch (BacktrackException bt) {
return false;
} finally {
backup(m);
}
}
protected boolean canBeCastExpression() throws EndOfFileException {
IToken m= mark();
try {
// The parenthesis cannot be followed by a binary operator
skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI);
switch (LTcatchEOF(1)) {
case IToken.tAMPERASSIGN:
case IToken.tAND:
case IToken.tARROW:
case IToken.tARROWSTAR:
case IToken.tASSIGN:
case IToken.tBITOR:
case IToken.tBITORASSIGN:
case IToken.tCOLON:
case IToken.tCOMMA:
case IToken.tDIV:
case IToken.tDIVASSIGN:
case IToken.tDOT:
case IToken.tDOTSTAR:
case IToken.tEQUAL:
case IToken.tGT:
case IToken.tGT_in_SHIFTR:
case IToken.tGTEQUAL:
case IToken.tLBRACKET:
case IToken.tLTEQUAL:
case IToken.tMINUSASSIGN:
case IToken.tMOD:
case IToken.tMODASSIGN:
case IToken.tNOTEQUAL:
case IToken.tOR:
case IToken.tPLUSASSIGN:
case IToken.tQUESTION:
case IToken.tRBRACE:
case IToken.tRBRACKET:
case IToken.tRPAREN:
case IToken.tSEMI:
case IToken.tSHIFTL:
case IToken.tSHIFTLASSIGN:
case IToken.tSHIFTR:
case IToken.tSHIFTRASSIGN:
case IToken.tSTARASSIGN:
return false;
}
return true;
} catch (BacktrackException bt) {
return false;
} finally {
backup(m);
}
}
protected boolean canBeTypeSpecifier() throws EndOfFileException {
@ -2511,12 +2570,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
}
}
protected void skipBrackets(int left, int right) throws EndOfFileException, BacktrackException {
protected void skipBrackets(int left, int right, int terminator) throws EndOfFileException, BacktrackException {
consume(left);
int nesting= 0;
while(true) {
final int lt1= LT(1);
if (lt1 == IToken.tEOC)
if (lt1 == IToken.tEOC || lt1 == terminator)
throwBacktrack(LA(1));
consume();

View file

@ -29,16 +29,17 @@ public class DeclarationOptions {
final public static int ALLOW_FOLLOWED_BY_BRACE= 0x1000;
final public static int ALLOW_OPAQUE_ENUM= 0x2000;
final public static int SINGLE_DTOR= 0x4000;
final public static int ALLOW_FUNCTION_DEFINITION= 0x8000;
public static final DeclarationOptions
GLOBAL= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_OPAQUE_ENUM),
FUNCTION_STYLE_ASM= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | NO_INITIALIZER | ALLOW_ABSTRACT),
GLOBAL= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_OPAQUE_ENUM | ALLOW_FUNCTION_DEFINITION),
FUNCTION_STYLE_ASM= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | NO_INITIALIZER | ALLOW_ABSTRACT | ALLOW_FUNCTION_DEFINITION),
C_MEMBER= new DeclarationOptions(ALLOW_BITFIELD | ALLOW_ABSTRACT),
CPP_MEMBER= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_BITFIELD | NO_CTOR_STYLE_INITIALIZER),
CPP_MEMBER= new DeclarationOptions(ALLOW_EMPTY_SPECIFIER | ALLOW_BITFIELD | NO_CTOR_STYLE_INITIALIZER | ALLOW_FUNCTION_DEFINITION),
LOCAL= new DeclarationOptions(ALLOW_OPAQUE_ENUM),
PARAMETER= new DeclarationOptions(ALLOW_ABSTRACT | ALLOW_PARAMETER_PACKS | REQUIRE_SIMPLE_NAME | NO_BRACED_INITIALIZER | NO_CTOR_STYLE_INITIALIZER),
TYPEID= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER),
TYPEID_TRAILING_RETURN_TYPE= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | ALLOW_FOLLOWED_BY_BRACE),
TYPEID_TRAILING_RETURN_TYPE= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | ALLOW_FOLLOWED_BY_BRACE | ALLOW_FUNCTION_DEFINITION),
TYPEID_NEW= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | NO_FUNCTIONS | NO_NESTED | ALLOW_FOLLOWED_BY_BRACE),
TYPEID_CONVERSION= new DeclarationOptions(REQUIRE_ABSTRACT | NO_INITIALIZER | NO_FUNCTIONS | NO_NESTED),
EXCEPTION= new DeclarationOptions(ALLOW_ABSTRACT | NO_INITIALIZER),
@ -60,6 +61,7 @@ public class DeclarationOptions {
final public boolean fRequireSimpleName;
final public boolean fAllowOpaqueEnum;
final public boolean fSingleDtor;
final public boolean fAllowFunctionDefinition;
public DeclarationOptions(int options) {
fAllowEmptySpecifier= (options & ALLOW_EMPTY_SPECIFIER) != 0;
@ -76,5 +78,6 @@ public class DeclarationOptions {
fCanBeFollowedByBrace= fAllowBracedInitializer || (options & ALLOW_FOLLOWED_BY_BRACE) != 0;
fAllowOpaqueEnum= (options & ALLOW_OPAQUE_ENUM) != 0;
fSingleDtor= (options & SINGLE_DTOR) != 0;
fAllowFunctionDefinition= (options & ALLOW_FUNCTION_DEFINITION) != 0;
}
}

View file

@ -1754,7 +1754,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
final IToken current = LA(1);
int startingOffset = current.getOffset();
if (current.getType() == IToken.tLBRACKET && supportParameterInfoBlock) {
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET);
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0);
}
IASTDeclSpecifier declSpec = null;

View file

@ -19,21 +19,23 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
* Reference operator for declarators.
*/
public class CPPASTReferenceOperator extends ASTNode implements ICPPASTReferenceOperator {
private final boolean fIsRValue;
public CPPASTReferenceOperator(boolean isRValueReference) {
fIsRValue= isRValueReference;
}
@Override
public boolean isRValueReference() {
return fIsRValue;
}
@Override
public CPPASTReferenceOperator copy() {
return copy(CopyStyle.withoutLocations);
}
@Override
public CPPASTReferenceOperator copy(CopyStyle style) {
CPPASTReferenceOperator copy = new CPPASTReferenceOperator(fIsRValue);
copy.setOffsetAndLength(this);

View file

@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
@ -40,6 +41,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
super(name);
}
@Override
public IASTExpression getDefault() {
IASTInitializerClause def= getDefaultClause();
if (def instanceof IASTExpression) {
@ -59,7 +61,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
IASTNode parent = name.getParent();
assert parent instanceof IASTDeclarator;
if (parent instanceof IASTDeclarator) {
IASTDeclarator dtor = (IASTDeclarator) parent;
IASTDeclarator dtor = ASTQueries.findOutermostDeclarator((IASTDeclarator) parent);
IASTInitializer initializer = dtor.getInitializer();
if (initializer instanceof IASTEqualsInitializer) {
return ((IASTEqualsInitializer) initializer).getInitializerClause();
@ -70,6 +72,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
return null;
}
@Override
public ICPPTemplateArgument getDefaultValue() {
IASTInitializerClause dc= getDefault();
IASTExpression d= null;
@ -96,6 +99,7 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
return new CPPTemplateArgument(val, t);
}
@Override
public IType getType() {
if (type == null) {
IASTNode parent= getPrimaryDeclaration().getParent();
@ -110,28 +114,36 @@ public class CPPTemplateNonTypeParameter extends CPPTemplateParameter implements
return type;
}
@Override
public boolean isParameterPack() {
return getType() instanceof ICPPParameterPackType;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public boolean isExtern() {
return false;
}
@Override
public boolean isAuto() {
return false;
}
@Override
public boolean isRegister() {
return false;
}
@Override
public IValue getInitialValue() {
return null;
}
@Override
public boolean isExternC() {
return false;
}
@Override
public boolean isMutable() {
return false;
}

View file

@ -209,11 +209,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
}
private IASTName qualifiedName() throws BacktrackException, EndOfFileException {
return ambiguousQualifiedName(CastExprCtx.eNotInBExpr);
}
private IASTName ambiguousQualifiedName(CastExprCtx ctx) throws BacktrackException, EndOfFileException {
TemplateIdStrategy strat= new TemplateIdStrategy();
IToken m= mark();
for(;;) {
try {
return qualifiedName(strat, CastExprCtx.eNotInBExpr);
return qualifiedName(ctx, strat);
} catch (BacktrackException e) {
if (strat.setNextAlternative()) {
backup(m);
@ -227,8 +231,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
/**
* Parses a qualified name.
*/
private IASTName qualifiedName(ITemplateIdStrategy s, CastExprCtx ctx) throws BacktrackException, EndOfFileException {
final TemplateIdStrategy strat= (TemplateIdStrategy) s;
private IASTName qualifiedName(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
if (strat == null)
return ambiguousQualifiedName(ctx);
ICPPASTQualifiedName qname= null;
IASTName name= null;
final int offset= LA(1).getOffset();
@ -288,11 +294,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (haveArgs == -1) {
templateID= false;
} else if (haveArgs == 0) {
if (strat.ignoreTemplateID()) {
templateID= false;
} else {
strat.addTemplateName(name);
}
templateID= strat.shallParseAsTemplateID(name);
}
}
if (templateID) {
@ -350,7 +352,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return name;
}
private IASTName addTemplateArguments(IASTName templateName, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
private IASTName addTemplateArguments(IASTName templateName, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
// Parse for template arguments
consume(IToken.tLT);
List<IASTNode> list = templateArgumentList(strat);
@ -566,7 +568,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
}
}
private List<IASTNode> templateArgumentList(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
private List<IASTNode> templateArgumentList(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
int startingOffset = LA(1).getOffset();
int endOffset = 0;
List<IASTNode> list= null;
@ -596,7 +598,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return list;
}
private IASTNode templateArgument(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
private IASTNode templateArgument(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
IToken argStart = mark();
ICPPASTTypeId typeId= null;
int lt1= 0;
@ -742,7 +744,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return expression(ExprKind.eConstant, BinaryExprCtx.eNotInTemplateID, null, null);
}
private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
final boolean allowComma= kind==ExprKind.eExpression;
boolean allowAssignment= kind !=ExprKind.eConstant;
@ -750,12 +752,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return throwExpression();
}
final boolean handleVariants= strat == null;
if (handleVariants) {
strat= new TemplateIdStrategy();
}
final int startOffset= expr != null ? ((ASTNode) expr).getOffset() : LA(1).getOffset();
int lt1;
int conditionCount= 0;
@ -763,7 +759,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
NameOrTemplateIDVariants variants= null;
if (expr == null) {
Object e = castExpressionForBinaryExpression(handleVariants, strat);
Object e = castExpressionForBinaryExpression(strat);
if (e instanceof IASTExpression) {
expr= (IASTExpression) e;
} else {
@ -934,7 +930,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// Cast expression
IToken m= mark();
try {
Object e = castExpressionForBinaryExpression(handleVariants, strat);
Object e = castExpressionForBinaryExpression(strat);
if (e instanceof IASTExpression) {
expr= (IASTExpression) e;
} else {
@ -999,18 +995,19 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
return buildExpression(lastOperator, expr);
}
public Object castExpressionForBinaryExpression(boolean handleVariants, final TemplateIdStrategy strat)
public Object castExpressionForBinaryExpression(ITemplateIdStrategy s)
throws EndOfFileException, BacktrackException {
if (!handleVariants)
return castExpression(CastExprCtx.eDirectlyInBExpr, strat);
if (s != null) {
return castExpression(CastExprCtx.eDirectlyInBExpr, s);
}
TemplateIdStrategy strat= new TemplateIdStrategy();
Variant variants= null;
IASTExpression singleExpression= null;
IASTName[] firstNames= null;
final IToken mark= mark();
IToken lastToken= null;
strat.reset();
for(;;) {
try {
IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat);
@ -1454,6 +1451,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// ( type-name ) { initializer-list , }
IToken m = mark();
try {
if (canBeCompoundLiteral()) {
int offset = consume().getOffset();
IASTTypeId t= typeId(DeclarationOptions.TYPEID);
consume(IToken.tRPAREN);
@ -1463,6 +1461,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
setRange(firstExpression, offset, calculateEndOffset(i));
break;
}
}
} catch (BacktrackException bt) {
}
backup(m);
@ -1554,7 +1553,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
isTemplate = true;
}
IASTName name = qualifiedName(strat, ctx);
IASTName name = qualifiedName(ctx, strat);
if (name == null)
throwBacktrack(((ASTNode) firstExpression).getOffset(),
@ -1577,7 +1576,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
isTemplate = true;
}
name = qualifiedName(strat, ctx);
name = qualifiedName(ctx, strat);
if (name == null)
throwBacktrack(((ASTNode) firstExpression).getOffset(),
@ -1690,7 +1689,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.t_operator:
case IToken.tCOMPLETION:
case IToken.tBITCOMPLEMENT: {
IASTName name = qualifiedName(strat, ctx);
IASTName name = qualifiedName(ctx, strat);
IASTIdExpression idExpression = nodeFactory.newIdExpression(name);
((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset()
+ ((ASTNode) name).getLength() - ((ASTNode) name).getOffset());
@ -2388,7 +2387,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
case IToken.t_try:
case IToken.tLBRACE:
case IToken.tASSIGN: // defaulted or deleted function definition
if (declarators.length != 1)
if (declarators.length != 1 || !declOption.fAllowFunctionDefinition)
throwBacktrack(LA(1));
dtor= declarators[0];
@ -2568,7 +2567,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
final int startOffset= LA(1).getOffset();
if (LT(1) == IToken.tLBRACKET && supportParameterInfoBlock) {
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET);
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0);
}
IASTDeclSpecifier declSpec= null;

View file

@ -14,6 +14,8 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.BitSet;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.ITemplateIdStrategy;
@ -27,50 +29,52 @@ final class TemplateIdStrategy implements ITemplateIdStrategy {
private IASTName[] fTemplateNames;
public TemplateIdStrategy() {
reset();
}
public void reset() {
fCurrentBranchPoint= -1;
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
if (fSimpleIDs != null) {
fSimpleIDs.clear();
}
}
public boolean ignoreTemplateID() {
@Override
public boolean shallParseAsTemplateID(IASTName name) {
fCurrentBranchPoint++;
return fSimpleIDs == null ? false : fSimpleIDs.get(fCurrentBranchPoint);
}
public void addTemplateName(IASTName name) {
boolean templateID= fSimpleIDs == null || !fSimpleIDs.get(fCurrentBranchPoint);
if (templateID) {
fTemplateNames= ArrayUtil.append(fTemplateNames, name);
}
return templateID;
}
public boolean setNextAlternative() {
final int bp = fCurrentBranchPoint;
int bp = fCurrentBranchPoint;
if (bp < 0)
return false;
fCurrentBranchPoint= -1;
IASTName[] names = getTemplateNames();
int nameLen= names.length;
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
if (fSimpleIDs == null) {
fSimpleIDs= new BitSet();
}
// Set a new branch as far right as possible.
final int len = fSimpleIDs.length();
if (len <= bp) {
while (bp >= 0) {
if (!fSimpleIDs.get(bp)) {
if (nameLen == 0 || !hasMultipleArgs(names[--nameLen])) {
fSimpleIDs.clear(bp+1, Integer.MAX_VALUE);
fSimpleIDs.set(bp);
return true;
}
for (int branch= Math.min(bp, len-2); branch>=0; branch--) {
if (!fSimpleIDs.get(branch)) {
fSimpleIDs.clear(branch+1, len);
fSimpleIDs.set(branch);
return true;
}
bp--;
}
return false;
}
private boolean hasMultipleArgs(IASTName templateName) {
IASTNode parent= templateName.getParent();
if (parent instanceof ICPPASTTemplateId) {
return ((ICPPASTTemplateId) parent).getTemplateArguments().length > 1;
}
return false;
}

View file

@ -781,7 +781,9 @@ public class CPPSemantics {
data.foundItems = ArrayUtil.addAll(Object.class, (Object[]) data.foundItems, (Object[]) results);
}
} else {
data.foundItems = mergePrefixResults((CharArrayObjectMap) data.foundItems, results, scoped);
@SuppressWarnings("unchecked")
final CharArrayObjectMap<Object> oldItems = (CharArrayObjectMap<Object>) data.foundItems;
data.foundItems = mergePrefixResults(oldItems, results, scoped);
}
}
@ -791,15 +793,17 @@ public class CPPSemantics {
* @param scoped
* @return
*/
static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) {
static CharArrayObjectMap<Object> mergePrefixResults(CharArrayObjectMap<Object> dest, Object source, boolean scoped) {
if (source == null) return dest;
CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2);
CharArrayObjectMap<Object> resultMap = (dest != null) ? dest : new CharArrayObjectMap<Object>(2);
CharArrayObjectMap map = null;
CharArrayObjectMap<Object> map = null;
Object[] objs = null;
int size;
if (source instanceof CharArrayObjectMap) {
map = (CharArrayObjectMap) source;
@SuppressWarnings("unchecked")
final CharArrayObjectMap<Object> sourceMap = (CharArrayObjectMap<Object>) source;
map = sourceMap;
size= map.size();
} else {
if (source instanceof Object[])
@ -3499,7 +3503,7 @@ public class CPPSemantics {
LookupData data = createLookupData(name);
data.contentAssist = true;
data.prefixLookup = prefixLookup;
data.foundItems = new CharArrayObjectMap(2);
data.foundItems = new CharArrayObjectMap<Object>(2);
// Convert namespaces to scopes.
List<ICPPScope> nsScopes= new ArrayList<ICPPScope>();
@ -3567,7 +3571,8 @@ public class CPPSemantics {
}
} catch (DOMException e) {
}
CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems;
@SuppressWarnings("unchecked")
CharArrayObjectMap<Object> map = (CharArrayObjectMap<Object>) data.foundItems;
IBinding[] result = IBinding.EMPTY_BINDING_ARRAY;
if (!map.isEmpty()) {
char[] key = null;
@ -3686,7 +3691,7 @@ public class CPPSemantics {
return true;
}
private static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) {
static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) {
if (tp1.isParameterPack() != tp2.isParameterPack())
return false;

View file

@ -460,10 +460,9 @@ public class CPPVisitor extends ASTQueries {
}
try {
boolean template = false;
ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name);
ICPPScope scope = (ICPPScope) getContainingScope(name);
while (scope instanceof ICPPTemplateScope) {
template = true;
scope= (ICPPScope) scope.getParent();
}
@ -493,14 +492,35 @@ public class CPPVisitor extends ASTQueries {
if (binding instanceof ICPPClassType) {
final ICPPInternalBinding ib = (ICPPInternalBinding) binding;
if ((binding instanceof ICPPClassTemplate) == template) {
if (templateParametersMatch((ICPPClassType) binding, templateDecl)) {
ib.addDeclaration(elabType);
return binding;
}
if (CPPSemantics.declaredBefore(binding, name, false)) {
if (CPPSemantics.declaredBefore(ib, name, false)) {
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION);
}
markRedeclaration(ib);
}
}
// Create a binding
if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) {
if (templateDecl != null)
binding = new CPPClassTemplate(name);
else
binding = new CPPClassType(name, binding);
// name may live in a different scope, so make sure to add it to the owner scope, as well.
ASTInternal.addName(scope, elabType.getName());
}
} catch (DOMException e) {
binding = e.getProblem();
}
return binding;
}
public static void markRedeclaration(final ICPPInternalBinding ib) {
// Mark the other declarations as problem and create the binding
final IASTNode[] decls = ib.getDeclarations();
if (decls != null) {
@ -517,22 +537,30 @@ public class CPPVisitor extends ASTQueries {
n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDEFINITION));
}
}
}
// Create a binding
if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) {
if (template)
binding = new CPPClassTemplate(name);
else
binding = new CPPClassType(name, binding);
// name may live in a different scope, so make sure to add it to the owner scope, as well.
ASTInternal.addName(scope, elabType.getName());
}
} catch (DOMException e) {
binding = e.getProblem();
}
/**
* Tests whether a class binding matches the template parameters of another declaration
*/
private static boolean templateParametersMatch(ICPPClassType binding,
ICPPASTTemplateDeclaration templateDecl) {
final boolean isTemplate= binding instanceof ICPPClassTemplate;
if (templateDecl == null)
return !isTemplate;
if (!isTemplate)
return false;
return binding;
ICPPTemplateParameter[] pars1 = ((ICPPClassTemplate) binding).getTemplateParameters();
ICPPASTTemplateParameter[] pars2 = templateDecl.getTemplateParameters();
int i=0;
for (ICPPASTTemplateParameter p2 : pars2) {
if (i >= pars1.length)
return true;
if (!CPPSemantics.isSameTemplateParameter(pars1[i++], p2))
return false;
}
return true;
}
private static IBinding createBinding(ICPPASTCompositeTypeSpecifier compType) {
@ -541,39 +569,43 @@ public class CPPVisitor extends ASTQueries {
IASTName[] ns = ((ICPPASTQualifiedName) name).getNames();
name = ns[ns.length - 1];
}
if (name instanceof ICPPASTTemplateId)
return CPPTemplates.createBinding((ICPPASTTemplateId) name);
IBinding binding = null;
ICPPScope scope = (ICPPScope) getContainingScope(name);
try {
boolean template = false;
while (scope instanceof ICPPTemplateScope) {
template = true;
scope= (ICPPScope) scope.getParent();
}
if (name instanceof ICPPASTTemplateId) {
return CPPTemplates.createBinding((ICPPASTTemplateId) name);
}
if (name.getLookupKey().length > 0 && scope != null) // can't lookup anonymous things
binding = scope.getBinding(name, false);
if (binding instanceof ICPPInternalBinding && binding instanceof ICPPClassType && name.isActive()) {
ICPPInternalBinding internal = (ICPPInternalBinding) binding;
if (internal.getDefinition() == null && (binding instanceof ICPPClassTemplate) == template) {
ASTInternal.addDefinition(internal, compType);
} else {
binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION);
}
} else {
if (template) {
binding = new CPPClassTemplate(name);
} else {
binding = new CPPClassType(name, binding);
}
}
} catch (DOMException e) {
binding = e.getProblem();
return e.getProblem();
}
// Can't lookup anonymous names
IBinding binding= null;
ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name);
if (name.getLookupKey().length > 0 && scope != null) {
binding = scope.getBinding(name, false);
if (binding instanceof ICPPInternalBinding
&& binding instanceof ICPPClassType && name.isActive()) {
ICPPInternalBinding ib = (ICPPInternalBinding) binding;
if (ib.getDefinition() == null
&& templateParametersMatch((ICPPClassType) binding, templateDecl)) {
ASTInternal.addDefinition(ib, compType);
return binding;
}
if (CPPSemantics.declaredBefore(ib, name, false)) {
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION);
}
markRedeclaration(ib);
}
}
if (templateDecl != null)
return new CPPClassTemplate(name);
return new CPPClassType(name, binding);
}
private static IBinding createBinding(IASTDeclaration declaration) {
if (declaration instanceof ICPPASTNamespaceDefinition) {

View file

@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
@ -110,6 +111,7 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
return IIndexCPPBindingConstants.CPPMETHOD;
}
@Override
public boolean isVirtual() {
return getBit(getAnnotation1(), PDOMCPPAnnotation.VIRTUAL_OFFSET);
}
@ -120,10 +122,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
return annotation1;
}
@Override
public boolean isPureVirtual() {
return getBit(getAnnotation1(), PDOMCPPAnnotation.PURE_VIRTUAL_OFFSET);
}
@Override
public boolean isDestructor() {
return getBit(getAnnotation1(), PDOMCPPAnnotation.DESTRUCTOR_OFFSET);
}
@ -133,10 +137,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
return false;
}
@Override
public boolean isImplicit() {
return getBit(getAnnotation1(), PDOMCPPAnnotation.IMPLICIT_METHOD_OFFSET);
}
@Override
public boolean isExplicit() {
return getBit(getAnnotation1(), PDOMCPPAnnotation.EXPLICIT_METHOD_OFFSET);
}
@ -169,10 +175,12 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
return false;
}
@Override
public int getVisibility() {
return PDOMCPPAnnotation.getVisibility(getAnnotation());
}
@Override
public ICPPClassType getClassOwner() {
return (ICPPClassType) getOwner();
}
@ -194,8 +202,19 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
public int getAdditionalNameFlags(int standardFlags, IASTName name) {
if ((standardFlags & PDOMName.IS_REFERENCE) == PDOMName.IS_REFERENCE) {
IASTNode parent= name.getParent();
if (parent instanceof ICPPASTFieldReference) {
// the name is not qualified
if (parent instanceof ICPPASTQualifiedName) {
// When taking the address of a method it will be called without suppressing
// the virtual mechanism
parent= parent.getParent();
if (parent instanceof IASTIdExpression) {
parent= parent.getParent();
if (parent instanceof IASTUnaryExpression) {
if (((IASTUnaryExpression) parent).getOperator() == IASTUnaryExpression.op_amper)
return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL;
}
}
} else if (parent instanceof ICPPASTFieldReference) {
// The name is not qualified
ICPPASTFieldReference fr= (ICPPASTFieldReference) parent;
parent= parent.getParent();
if (parent instanceof IASTFunctionCallExpression) {
@ -221,9 +240,8 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL;
}
}
}
// calling a member from within a member
else if (parent instanceof IASTIdExpression) {
} else if (parent instanceof IASTIdExpression) {
// Calling a member from within a member
if (parent.getParent() instanceof IASTFunctionCallExpression) {
return PDOMName.COULD_BE_POLYMORPHIC_METHOD_CALL;
}

View file

@ -30,7 +30,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -70,7 +70,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -132,7 +132,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -177,7 +177,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -240,7 +240,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -281,7 +281,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -343,7 +343,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -384,7 +384,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -450,7 +450,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -499,7 +499,7 @@ public:
this->systemId = systemId;
}
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -704,53 +704,37 @@ class test {
#endif /* TEST_H_ */
//!Generate Getters and Setters One Getter Selection Separate Definition
//!Generate Getters and Setters, Pass by Reference, Separate Definition
//#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest
//@.config
filename=C.h
getters=name
setters=name
definitionSeparate=true
//@C.cpp
#include "C.h"
int Person::SocSecNo() {
return socSecNo;
}
int main(int argc, char** argv) {
}
//=
#include "C.h"
char* Person::getName() const {
return name;
}
int Person::SocSecNo() {
return socSecNo;
}
int main(int argc, char** argv) {
}
//@C.h
#ifndef C_H_
#define C_H_
struct FullName {
const char* first;
const char* last;
FullName(const FullName& other);
~FullName();
};
class Person {
private:
int systemId;
protected:
char* name;
FullName name;
public:
const int socSecNo;
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -774,20 +758,28 @@ int gooo = 1;
#ifndef C_H_
#define C_H_
struct FullName {
const char* first;
const char* last;
FullName(const FullName& other);
~FullName();
};
class Person {
private:
int systemId;
protected:
char* name;
FullName name;
public:
const int socSecNo;
Person myFriend;
char* getName() const;
const FullName& getName() const;
void setName(const FullName& name);
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -807,6 +799,34 @@ public:
int gooo = 1;
#endif /* C_H_ */
//@C.cpp
#include "C.h"
int Person::SocSecNo() {
return socSecNo;
}
int main(int argc, char** argv) {
}
//=
#include "C.h"
const FullName& Person::getName() const {
return name;
}
void Person::setName(const FullName& name) {
this->name = name;
}
int Person::SocSecNo() {
return socSecNo;
}
int main(int argc, char** argv) {
}
//!Generate Getters and Setters One Getter Selection with Namespace Separate Definition
//#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest
//@.config
@ -863,7 +883,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -908,7 +928,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -984,7 +1004,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -1025,7 +1045,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -1102,7 +1122,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor
@ -1144,7 +1164,7 @@ public:
Person myFriend;
Person(int socSecNo); // contructor
Person(int socSecNo); // constructor
~Person(); // destructor

View file

@ -130,7 +130,7 @@ public class CHQueries {
if (CallHierarchyUI.isRelevantForCallHierarchy(binding)) {
while (true) {
ICElement[] defs= null;
if (binding instanceof ICPPMethod) {
if (binding instanceof ICPPMethod && name.couldBePolymorphicMethodCall()) {
defs = findOverriders(index, (ICPPMethod) binding);
}
if (defs == null) {

View file

@ -24,7 +24,9 @@ import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.rewrite.TypeHelper;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTBinaryExpression;
@ -37,28 +39,39 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTParameterDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReferenceOperator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
public class FunctionFactory {
public class GetterSetterFactory {
private final IASTName fieldName;
private final IASTSimpleDeclaration fieldDeclaration;
private boolean passByReference;
public static IASTFunctionDefinition createGetterDefinition(IASTName fieldName,
IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) {
public GetterSetterFactory(IASTName fieldName, IASTSimpleDeclaration fieldDeclaration) {
this.fieldName = fieldName;
this.fieldDeclaration = fieldDeclaration;
IType type = CPPVisitor.createType(fieldDeclaration.getDeclSpecifier());
passByReference = TypeHelper.shouldBePassedByReference(type, fieldDeclaration.getTranslationUnit());
}
public IASTFunctionDefinition createGetterDefinition(ICPPASTQualifiedName qualifiedName) {
IASTFunctionDefinition getter = new CPPASTFunctionDefinition();
getter.setDeclSpecifier(fieldDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations));
IASTDeclarator getterDeclarator = getGetterDeclarator(fieldName, fieldDeclaration, name);
// IASTFunctionDefinition. expects the outermost IASTFunctionDeclarator in declarator hierarchy
getter.setDeclSpecifier(getParamOrReturnDeclSpecifier());
IASTDeclarator getterDeclarator = getGetterDeclarator(qualifiedName);
// IASTFunctionDefinition expects the outermost IASTFunctionDeclarator in declarator hierarchy
while (!(getterDeclarator instanceof IASTFunctionDeclarator)) {
getterDeclarator = getterDeclarator.getNestedDeclarator();
}
getter.setDeclarator((IASTFunctionDeclarator) getterDeclarator);
getter.setBody(getGetterBody(fieldName));
getter.setBody(getGetterBody());
return getter;
}
private static CPPASTCompoundStatement getGetterBody(IASTName fieldName) {
private CPPASTCompoundStatement getGetterBody() {
CPPASTCompoundStatement compound = new CPPASTCompoundStatement();
CPPASTReturnStatement returnStatement = new CPPASTReturnStatement();
CPPASTIdExpression idExpr = new CPPASTIdExpression();
@ -70,36 +83,38 @@ public class FunctionFactory {
return compound;
}
private static IASTDeclarator getGetterDeclarator(IASTName fieldName,
IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) {
private IASTDeclarator getGetterDeclarator(ICPPASTQualifiedName qualifiedName) {
CPPASTName getterName = new CPPASTName();
getterName.setName(GetterSetterNameGenerator.generateGetterName(fieldName).toCharArray());
// copy declarator hierarchy
// Copy declarator hierarchy
IASTDeclarator topDeclarator = fieldDeclaration.getDeclarators()[0].copy(CopyStyle.withLocations);
// find the innermost declarator in hierarchy
// Find the innermost declarator in hierarchy
IASTDeclarator innermost = topDeclarator;
while (innermost.getNestedDeclarator() != null) {
innermost = innermost.getNestedDeclarator();
}
// create a new innermost function declarator basing on the field declarator
// Create a new innermost function declarator based on the field declarator
CPPASTFunctionDeclarator functionDeclarator = new CPPASTFunctionDeclarator();
functionDeclarator.setConst(true);
if (name != null) {
name.addName(getterName);
functionDeclarator.setName(name);
if (qualifiedName != null) {
qualifiedName.addName(getterName);
functionDeclarator.setName(qualifiedName);
} else {
functionDeclarator.setName(getterName);
}
for (IASTPointerOperator pointer : innermost.getPointerOperators()){
functionDeclarator.addPointerOperator(pointer.copy(CopyStyle.withLocations));
}
if (passByReference) {
functionDeclarator.addPointerOperator(new CPPASTReferenceOperator(false));
}
// replace innermost with functionDeclarator and return the whole declarator tree
// Replace the innermost with functionDeclarator and return the whole declarator tree
if (innermost == topDeclarator) {
// no tree
// No tree
return functionDeclarator;
} else {
IASTDeclarator parent = (IASTDeclarator) innermost.getParent();
@ -108,16 +123,15 @@ public class FunctionFactory {
}
}
public static IASTFunctionDefinition createSetterDefinition(IASTName fieldName,
IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) {
public IASTFunctionDefinition createSetterDefinition(ICPPASTQualifiedName qualifiedName) {
IASTFunctionDefinition setter = new CPPASTFunctionDefinition();
setter.setDeclSpecifier(getVoidDeclSpec());
setter.setDeclarator(getSetterDeclarator(fieldName, fieldDeclaration, name));
setter.setBody(getSetterBody(fieldDeclaration));
setter.setDeclarator(getSetterDeclarator(qualifiedName));
setter.setBody(getSetterBody());
return setter;
}
private static CPPASTCompoundStatement getSetterBody(IASTSimpleDeclaration fieldDeclaration) {
private CPPASTCompoundStatement getSetterBody() {
CPPASTCompoundStatement compound = new CPPASTCompoundStatement();
CPPASTExpressionStatement exprStmt = new CPPASTExpressionStatement();
CPPASTBinaryExpression binExpr = new CPPASTBinaryExpression();
@ -126,7 +140,7 @@ public class FunctionFactory {
innerDeclarator = innerDeclarator.getNestedDeclarator();
}
IASTName fieldName = innerDeclarator.getName();
CPPASTName parameterName = getSetterParameterName(fieldName);
CPPASTName parameterName = getSetterParameterName();
if (Arrays.equals(fieldName.getSimpleID(), parameterName.getSimpleID())) {
CPPASTFieldReference fieldRef = new CPPASTFieldReference();
CPPASTLiteralExpression litExpr = new CPPASTLiteralExpression();
@ -147,28 +161,29 @@ public class FunctionFactory {
return compound;
}
private static CPPASTFunctionDeclarator getSetterDeclarator(IASTName fieldName,
IASTSimpleDeclaration fieldDeclaration, ICPPASTQualifiedName name) {
private CPPASTFunctionDeclarator getSetterDeclarator(ICPPASTQualifiedName qualifiedName) {
CPPASTName setterName = new CPPASTName();
setterName.setName(GetterSetterNameGenerator.generateSetterName(fieldName).toCharArray());
CPPASTFunctionDeclarator declarator = new CPPASTFunctionDeclarator();
if (name != null) {
name.addName(setterName);
declarator.setName(name);
if (qualifiedName != null) {
qualifiedName.addName(setterName);
declarator.setName(qualifiedName);
} else {
declarator.setName(setterName);
}
CPPASTParameterDeclaration parameterDeclaration = new CPPASTParameterDeclaration();
IASTDeclarator parameterDeclarator = fieldDeclaration.getDeclarators()[0].copy(CopyStyle.withLocations);
parameterDeclarator.setName(getSetterParameterName(fieldName));
parameterDeclarator.setName(getSetterParameterName());
if (passByReference) {
parameterDeclarator.addPointerOperator(new CPPASTReferenceOperator(false));
}
parameterDeclaration.setDeclarator(parameterDeclarator);
parameterDeclaration.setDeclSpecifier(fieldDeclaration.getDeclSpecifier().copy(
CopyStyle.withLocations));
parameterDeclaration.setDeclSpecifier(getParamOrReturnDeclSpecifier());
declarator.addParameterDeclaration(parameterDeclaration.copy(CopyStyle.withLocations));
return declarator;
}
private static CPPASTName getSetterParameterName(IASTName fieldName) {
private CPPASTName getSetterParameterName() {
String parameterName = GetterSetterNameGenerator.generateSetterParameterName(fieldName);
return new CPPASTName(parameterName.toCharArray());
}
@ -179,25 +194,25 @@ public class FunctionFactory {
return declSpecifier;
}
public static IASTSimpleDeclaration createGetterDeclaration(IASTName fieldName,
IASTSimpleDeclaration fieldDeclaration) {
public IASTSimpleDeclaration createGetterDeclaration() {
IASTSimpleDeclaration getter = new CPPASTSimpleDeclaration();
IASTDeclSpecifier declSpec = fieldDeclaration.getDeclSpecifier();
getter.setDeclSpecifier(declSpec.copy(CopyStyle.withLocations));
// TODO(sprigogin): Implement return by reference
// IType type = CPPVisitor.createType(declSpec);
// if (TypeHelper.shouldBePassedByReference(type, fieldDeclaration.getTranslationUnit())) {
// declSpec.s
// }
getter.addDeclarator(getGetterDeclarator(fieldName, fieldDeclaration, null));
getter.setDeclSpecifier(getParamOrReturnDeclSpecifier());
getter.addDeclarator(getGetterDeclarator(null));
return getter;
}
public static IASTSimpleDeclaration createSetterDeclaration(IASTName fieldName,
IASTSimpleDeclaration fieldDeclaration) {
private IASTDeclSpecifier getParamOrReturnDeclSpecifier() {
IASTDeclSpecifier declSpec = fieldDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations);
if (passByReference) {
declSpec.setConst(true);
}
return declSpec;
}
public IASTSimpleDeclaration createSetterDeclaration() {
IASTSimpleDeclaration setter = new CPPASTSimpleDeclaration();
setter.setDeclSpecifier(getVoidDeclSpec());
setter.addDeclarator(getSetterDeclarator(fieldName, fieldDeclaration, null));
setter.addDeclarator(getSetterDeclarator(null));
return setter;
}
}

View file

@ -31,14 +31,14 @@ public class GetterSetterInsertEditProvider implements Comparable<GetterSetterIn
private IASTSimpleDeclaration functionDeclaration;
private AccessorKind kind;
private IASTName fieldName;
private IASTSimpleDeclaration fieldDeclaration;
private GetterSetterFactory getterSetterFactory;
public GetterSetterInsertEditProvider(IASTName fieldName, IASTSimpleDeclaration fieldDeclaration,
AccessorKind kind) {
this.kind = kind;
this.fieldName = fieldName;
this.fieldDeclaration = fieldDeclaration;
this.getterSetterFactory = new GetterSetterFactory(fieldName, fieldDeclaration);
createFunctionDeclaration();
}
@ -46,10 +46,10 @@ public class GetterSetterInsertEditProvider implements Comparable<GetterSetterIn
public void createFunctionDeclaration() {
switch (this.kind) {
case GETTER:
this.functionDeclaration = FunctionFactory.createGetterDeclaration(fieldName, fieldDeclaration);
this.functionDeclaration = getterSetterFactory.createGetterDeclaration();
break;
case SETTER:
this.functionDeclaration = FunctionFactory.createSetterDeclaration(fieldName, fieldDeclaration);
this.functionDeclaration = getterSetterFactory.createSetterDeclaration();
break;
}
}
@ -67,23 +67,23 @@ public class GetterSetterInsertEditProvider implements Comparable<GetterSetterIn
IASTFunctionDefinition definition = null;
ICPPASTQualifiedName qname;
if (qualifedName) {
qname = getClassname();
qname = getClassName();
} else {
qname = null;
}
switch (kind) {
case GETTER:
definition = FunctionFactory.createGetterDefinition(fieldName, fieldDeclaration, qname);
definition = getterSetterFactory.createGetterDefinition(qname);
break;
case SETTER:
definition = FunctionFactory.createSetterDefinition(fieldName, fieldDeclaration, qname);
definition = getterSetterFactory.createSetterDefinition(qname);
break;
}
return definition;
}
private ICPPASTQualifiedName getClassname() {
private ICPPASTQualifiedName getClassName() {
IASTNode node = fieldDeclaration.getParent();
while (!(node instanceof IASTCompositeTypeSpecifier)) {
node = node.getParent();

View file

@ -84,6 +84,7 @@ public class CReconciler extends MonoReconciler {
/*
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
@Override
public boolean contains(ISchedulingRule rule) {
return rule == this;
}
@ -91,6 +92,7 @@ public class CReconciler extends MonoReconciler {
/*
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule)
*/
@Override
public boolean isConflicting(ISchedulingRule rule) {
return rule == this;
}
@ -104,26 +106,31 @@ public class CReconciler extends MonoReconciler {
/*
* @see org.eclipse.ui.IPartListener2#partActivated(org.eclipse.ui.IWorkbenchPartReference)
*/
@Override
public void partActivated(IWorkbenchPartReference partRef) {
}
/*
* @see org.eclipse.ui.IPartListener2#partBroughtToTop(org.eclipse.ui.IWorkbenchPartReference)
*/
@Override
public void partBroughtToTop(IWorkbenchPartReference partRef) {
}
/*
* @see org.eclipse.ui.IPartListener2#partClosed(org.eclipse.ui.IWorkbenchPartReference)
*/
@Override
public void partClosed(IWorkbenchPartReference partRef) {
}
/*
* @see org.eclipse.ui.IPartListener2#partDeactivated(org.eclipse.ui.IWorkbenchPartReference)
*/
@Override
public void partDeactivated(IWorkbenchPartReference partRef) {
}
/*
* @see org.eclipse.ui.IPartListener2#partHidden(org.eclipse.ui.IWorkbenchPartReference)
*/
@Override
public void partHidden(IWorkbenchPartReference partRef) {
if (partRef.getPart(false) == fTextEditor) {
setEditorActive(false);
@ -132,16 +139,19 @@ public class CReconciler extends MonoReconciler {
/*
* @see org.eclipse.ui.IPartListener2#partInputChanged(org.eclipse.ui.IWorkbenchPartReference)
*/
@Override
public void partInputChanged(IWorkbenchPartReference partRef) {
}
/*
* @see org.eclipse.ui.IPartListener2#partOpened(org.eclipse.ui.IWorkbenchPartReference)
*/
@Override
public void partOpened(IWorkbenchPartReference partRef) {
}
/*
* @see org.eclipse.ui.IPartListener2#partVisible(org.eclipse.ui.IWorkbenchPartReference)
*/
@Override
public void partVisible(IWorkbenchPartReference partRef) {
if (partRef.getPart(false) == fTextEditor) {
CReconciler.this.scheduleReconciling();
@ -192,6 +202,7 @@ public class CReconciler extends MonoReconciler {
/*
* @see org.eclipse.cdt.core.model.IElementChangedListener#elementChanged(org.eclipse.cdt.core.model.ElementChangedEvent)
*/
@Override
public void elementChanged(ElementChangedEvent event) {
if (event.getType() == ElementChangedEvent.POST_CHANGE) {
if (isRelevantDelta(event.getDelta())) {
@ -209,10 +220,7 @@ public class CReconciler extends MonoReconciler {
if ((flags & ICElementDelta.F_CONTENT) != 0) {
if (!fIsReconciling && isRelevantElement(delta.getElement())) {
// mark model changed, but don't update immediately
fIndexerListener.ignoreChanges(false);
setCModelChanged(true);
} else if (delta.getElement() instanceof ITranslationUnit) {
fIndexerListener.ignoreChanges(true);
}
}
if ((flags & (
@ -237,11 +245,11 @@ public class CReconciler extends MonoReconciler {
private class IndexerListener implements IIndexerStateListener, IIndexChangeListener {
private boolean fIndexChanged;
private boolean fIgnoreChanges;
/*
* @see org.eclipse.cdt.core.index.IIndexerStateListener#indexChanged(org.eclipse.cdt.core.index.IIndexerStateEvent)
*/
@Override
public void indexChanged(IIndexerStateEvent event) {
if (event.indexerIsIdle()) {
if (fIndexChanged || hasCModelChanged()) {
@ -252,27 +260,20 @@ public class CReconciler extends MonoReconciler {
setCModelChanged(true);
}
}
fIgnoreChanges= false;
}
}
public void ignoreChanges(boolean ignore) {
fIgnoreChanges= ignore;
}
/*
* @see org.eclipse.cdt.core.index.IIndexChangeListener#indexChanged(org.eclipse.cdt.core.index.IIndexChangeEvent)
*/
@Override
public void indexChanged(IIndexChangeEvent event) {
if (!fIndexChanged && isRelevantProject(event.getAffectedProject())) {
if (!fIgnoreChanges || event.isCleared() || event.isReloaded() || event.hasNewFile()) {
fIndexChanged= true;
}
}
}
}
/** The reconciler's editor */
private ITextEditor fTextEditor;
/** The part listener */
@ -328,6 +329,7 @@ public class CReconciler extends MonoReconciler {
CCorePlugin.getIndexManager().addIndexChangeListener(fIndexerListener);
fTriggerReconcilerJob= new SingletonJob("Trigger Reconciler", new Runnable() { //$NON-NLS-1$
@Override
public void run() {
forceReconciling();
}});

View file

@ -100,9 +100,11 @@ public class CSourceHover extends AbstractCEditorTextHover {
protected static class SingletonRule implements ISchedulingRule {
public static final ISchedulingRule INSTANCE = new SingletonRule();
@Override
public boolean contains(ISchedulingRule rule) {
return rule == this;
}
@Override
public boolean isConflicting(ISchedulingRule rule) {
return rule == this;
}
@ -132,6 +134,7 @@ public class CSourceHover extends AbstractCEditorTextHover {
/*
* @see org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable#runOnAST(org.eclipse.cdt.core.dom.ast.IASTTranslationUnit)
*/
@Override
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) {
if (ast != null) {
try {
@ -637,12 +640,8 @@ public class CSourceHover extends AbstractCEditorTextHover {
String[] sourceLines= Strings.convertIntoLines(source);
String firstLine= sourceLines[0];
if (firstLine.length() > 0 && !Character.isWhitespace(firstLine.charAt(0)))
sourceLines[0]= ""; //$NON-NLS-1$
Strings.trimIndentation(sourceLines, getTabWidth(), getTabWidth());
if (!Character.isWhitespace(firstLine.charAt(0)))
sourceLines[0]= firstLine;
boolean ignoreFirstLine= firstLine.length() > 0 && !Character.isWhitespace(firstLine.charAt(0));
Strings.trimIndentation(sourceLines, getTabWidth(), getTabWidth(), !ignoreFirstLine);
source = Strings.concatenate(sourceLines, delim);
return source;
@ -797,6 +796,7 @@ public class CSourceHover extends AbstractCEditorTextHover {
@Override
public IInformationControlCreator getHoverControlCreator() {
return new IInformationControlCreator() {
@Override
public IInformationControl createInformationControl(Shell parent) {
IEditorPart editor= getEditor();
int orientation= SWT.NONE;
@ -814,6 +814,7 @@ public class CSourceHover extends AbstractCEditorTextHover {
@Override
public IInformationControlCreator getInformationPresenterControlCreator() {
return new IInformationControlCreator() {
@Override
public IInformationControl createInformationControl(Shell parent) {
IEditorPart editor= getEditor();
int orientation= SWT.NONE;

View file

@ -61,6 +61,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
private String fErrorMessage;
@Override
public List<ICompletionProposal> computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) {
List<ICompletionProposal> proposals= Collections.emptyList();
fErrorMessage= null;
@ -81,17 +82,21 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
return proposals;
}
@Override
public List<IContextInformation> computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) {
return null;
}
@Override
public String getErrorMessage() {
return fErrorMessage;
}
@Override
public void sessionEnded() {
}
@Override
public void sessionStarted() {
}
@ -257,6 +262,9 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
final int prefixLength = namePrefix.length();
final IProject project= tu.getCProject().getProject();
File[] files= fileDir.listFiles();
if (files == null) {
return;
}
IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(namePrefix);
for (File file : files) {
final String name= file.getName();
@ -311,6 +319,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
final IProject project= tu.getCProject().getProject();
parent.accept(new IResourceProxyVisitor() {
boolean fFirstVisit= true;
@Override
public boolean visit(IResourceProxy proxy) throws CoreException {
final int type= proxy.getType();
final String name= proxy.getName();

View file

@ -192,7 +192,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
// editor.setAction("AddDelegateMethods", fAddDelegateMethods); //$NON-NLS-1$
//
// fAddUnimplementedConstructors= new AddUnimplementedConstructorsAction(editor);
// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONTRUCTORS);
// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONSTRUCTORS);
// editor.setAction("AddUnimplementedConstructors", fAddUnimplementedConstructors); //$NON-NLS-1$
//
// fGenerateConstructorUsingFields= new GenerateNewConstructorUsingFieldsAction(editor);
@ -277,7 +277,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
// fAddDelegateMethods.setActionDefinitionId(ICEditorActionDefinitionIds.CREATE_DELEGATE_METHODS);
//
// fAddUnimplementedConstructors= new AddUnimplementedConstructorsAction(site);
// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONTRUCTORS);
// fAddUnimplementedConstructors.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_UNIMPLEMENTED_CONSTRUCTORS);
//
// fGenerateConstructorUsingFields= new GenerateNewConstructorUsingFieldsAction(site);
// fGenerateConstructorUsingFields.setActionDefinitionId(ICEditorActionDefinitionIds.GENERATE_CONSTRUCTOR_USING_FIELDS);

View file

@ -80,7 +80,7 @@ public abstract class AbstractErrorParserBlock extends AbstractCOptionPage {
@Deprecated
public AbstractErrorParserBlock(Preferences prefs) {
this();
// usingDeprecatedContructor = true;
// usingDeprecatedConstructor = true;
fPrefs = prefs;
}

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.cdt.dsf" version="2">
<resource path="src/org/eclipse/cdt/dsf/concurrent/Transaction.java" type="org.eclipse.cdt.dsf.concurrent.Transaction">
<filter comment="Utility is not in common use. I changed erasure type for argument, but at worse this should only cause a warning." id="420679712">
<message_arguments>
<message_argument value="org.eclipse.cdt.dsf.concurrent.Transaction.validate(ICache&lt;?&gt;[])"/>
<message_argument value="T"/>
</message_arguments>
</filter>
</resource>
</component>

View file

@ -155,6 +155,27 @@ public abstract class AbstractCache<V> implements ICache<V> {
}
}
private void completeWaitingRms() {
Object waiting = null;
synchronized(this) {
waiting = fWaitingList;
fWaitingList = null;
}
if (waiting != null) {
if (waiting instanceof RequestMonitor) {
completeWaitingRm((RequestMonitor)waiting);
} else if (waiting instanceof RequestMonitor[]) {
RequestMonitor[] waitingList = (RequestMonitor[])waiting;
for (int i = 0; i < waitingList.length; i++) {
if (waitingList[i] != null) {
completeWaitingRm(waitingList[i]);
}
}
}
waiting = null;
}
}
private void completeWaitingRm(RequestMonitor rm) {
rm.setStatus(fStatus);
rm.removeCancelListener(fRequestCanceledListener);
@ -300,23 +321,33 @@ public abstract class AbstractCache<V> implements ICache<V> {
fStatus = status;
fValid = true;
Object waiting = null;
synchronized(this) {
waiting = fWaitingList;
fWaitingList = null;
}
if (waiting != null) {
if (waiting instanceof RequestMonitor) {
completeWaitingRm((RequestMonitor)waiting);
} else if (waiting instanceof RequestMonitor[]) {
RequestMonitor[] waitingList = (RequestMonitor[])waiting;
for (int i = 0; i < waitingList.length; i++) {
if (waitingList[i] != null) {
completeWaitingRm(waitingList[i]);
}
}
}
waiting = null;
completeWaitingRms();
}
/**
* Performs the set and reset operations in one step This allows the cache to
* remain in invalid state, but to notify any waiting listeners that the state of
* the cache has changed.
*
* @param data
* The data that should be returned to any clients waiting for
* cache data and for clients requesting data until the cache is
* invalidated.
* @status The status that should be returned to any clients waiting for
* cache data and for clients requesting data until the cache is
* invalidated
*
* @see #reset(Object, IStatus)
* @since 2.3
*/
protected void setAndReset(V data, IStatus status) {
assert fExecutor.getDsfExecutor().isInExecutorThread();
fData = data;
fStatus = status;
fValid = false;
completeWaitingRms();
}
}

View file

@ -107,8 +107,7 @@ abstract public class RangeCache<V> {
protected List<V> process() throws InvalidCacheException, CoreException {
clearCanceledRequests();
List<ICache<?>> transactionRequests = getRequests(fOffset, fCount);
List<Request> transactionRequests = getRequests(fOffset, fCount);
validate(transactionRequests);
return makeElementsListFromRequests(transactionRequests, fOffset, fCount);
@ -156,7 +155,7 @@ abstract public class RangeCache<V> {
public ICache<List<V>> getRange(final long offset, final int count) {
assert fExecutor.getDsfExecutor().isInExecutorThread();
List<ICache<?>> requests = getRequests(offset, count);
List<Request> requests = getRequests(offset, count);
RequestCache<List<V>> range = new RequestCache<List<V>>(fExecutor) {
@Override
@ -232,8 +231,8 @@ abstract public class RangeCache<V> {
}
}
private List<ICache<?>> getRequests(long fOffset, int fCount) {
List<ICache<?>> requests = new ArrayList<ICache<?>>(1);
private List<Request> getRequests(long fOffset, int fCount) {
List<Request> requests = new ArrayList<Request>(1);
// Create a new request for the data to retrieve.
Request current = new Request(fOffset, fCount);
@ -252,7 +251,7 @@ abstract public class RangeCache<V> {
// Adjust the beginning of the requested range of data. If there
// is already an overlapping range in front of the requested range,
// then use it.
private Request adjustRequestHead(Request request, List<ICache<?>> transactionRequests, long offset, int count) {
private Request adjustRequestHead(Request request, List<Request> transactionRequests, long offset, int count) {
SortedSet<Request> headRequests = fRequests.headSet(request);
if (!headRequests.isEmpty()) {
Request headRequest = headRequests.last();
@ -276,7 +275,7 @@ abstract public class RangeCache<V> {
* @param transactionRequests
* @return
*/
private Request adjustRequestTail(Request current, List<ICache<?>> transactionRequests, long offset, int count) {
private Request adjustRequestTail(Request current, List<Request> transactionRequests, long offset, int count) {
// Create a duplicate of the tailSet, in order to avoid a concurrent modification exception.
List<Request> tailSet = new ArrayList<Request>(fRequests.tailSet(current));
@ -313,14 +312,13 @@ abstract public class RangeCache<V> {
return current;
}
private List<V> makeElementsListFromRequests(List<ICache<?>> requests, long offset, int count) {
private List<V> makeElementsListFromRequests(List<Request> requests, long offset, int count) {
List<V> retVal = new ArrayList<V>(count);
long index = offset;
long end = offset + count;
int requestIdx = 0;
while (index < end ) {
@SuppressWarnings("unchecked")
Request request = (Request)requests.get(requestIdx);
Request request = requests.get(requestIdx);
if (index < request.fOffset + request.fCount) {
retVal.add( request.getData().get((int)(index - request.fOffset)) );
index ++;

View file

@ -94,4 +94,13 @@ public abstract class RequestCache<V> extends AbstractCache<V> {
}
super.set(data, status);
}
@Override
protected void reset() {
if (fRm != null) {
fRm.cancel();
fRm = null;
}
super.reset();
}
}

View file

@ -70,8 +70,10 @@ public abstract class Transaction<V> {
* logic once the cache object has been updated from the source.
*
* @return the cached data if it's valid, otherwise an exception is thrown
* @throws InvalidCacheException
* @throws CoreException
* @throws Transaction.InvalidCacheException Exception indicating that a
* cache is not valid and transaction will need to be rescheduled.
* @throws CoreException Exception indicating that one of the caches is
* in error state and transaction cannot be processed.
*/
abstract protected V process() throws InvalidCacheException, CoreException;
@ -149,7 +151,7 @@ public abstract class Transaction<V> {
* See {@link #validate(RequestCache)}. This variant simply validates
* multiple cache objects.
*/
public void validate(ICache<?> ... caches) throws InvalidCacheException, CoreException {
public <T> void validate(ICache<?> ... caches) throws InvalidCacheException, CoreException {
validate(Arrays.asList(caches));
}
@ -157,11 +159,12 @@ public abstract class Transaction<V> {
* See {@link #validate(RequestCache)}. This variant simply validates
* multiple cache objects.
*/
public void validate(Iterable<ICache<?>> caches) throws InvalidCacheException, CoreException {
public void validate(@SuppressWarnings("rawtypes") Iterable caches) throws InvalidCacheException, CoreException {
// Check if any of the caches have errors:
boolean allValid = true;
for (ICache<?> cache : caches) {
for (Object cacheObj : caches) {
ICache<?> cache = (ICache<?>)cacheObj;
if (cache.isValid()) {
if (!cache.getStatus().isOK()) {
throw new CoreException(cache.getStatus());
@ -181,7 +184,8 @@ public abstract class Transaction<V> {
}
};
int count = 0;
for (ICache<?> cache : caches) {
for (Object cacheObj : caches) {
ICache<?> cache = (ICache<?>)cacheObj;
if (!cache.isValid()) {
cache.update(countringRm);
count++;

View file

@ -0,0 +1,234 @@
/*******************************************************************************
* Copyright (c) 2011 Wind River Systems 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
//#ifdef exercises
package org.eclipse.cdt.examples.dsf.dataviewer;
//#else
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
//#endif
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
import org.eclipse.cdt.dsf.concurrent.ICache;
import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Transaction;
import org.eclipse.core.runtime.CoreException;
/**
* A data generator which performs a sum computation on data retrieved from a
* number of other data generators. The data retrieval from other generators
* is performed using ACPM caches and the result is calculated once all caches
* are valid.
* <p>
* Unlike {@link AsyncSumDataGenerator}, this data generator listens to events
* from the individual the data providers. Theve events are used to
* invalidate caches to make sure that they don't return incorrect data. This
* generator also sends out events to its clients to notify them to update, or
* invalidate their caches.
* </p>
*/
public class ACPMSumDataGenerator
implements IDataGenerator, IDataGenerator.Listener
{
/**
* DSF executor used to serialize data access within this data generator.
*/
final private DsfExecutor fExecutor;
/**
* Data generators to retrieve original data to perform calculations on.
* The generators are accessed through the cache manager wrappers.
*/
final private DataGeneratorCacheManager[] fDataGeneratorCMs;
/**
* List of listeners for this data generator.
*/
final private List<Listener> fListeners = new LinkedList<Listener>();
public ACPMSumDataGenerator(DsfExecutor executor,
IDataGenerator[] generators)
{
fExecutor = executor;
// Create wrappers for data generators and add ourselves as listener
// to their events.
fDataGeneratorCMs = new DataGeneratorCacheManager[generators.length];
ImmediateInDsfExecutor immediateExecutor =
new ImmediateInDsfExecutor(fExecutor);
for (int i = 0; i < generators.length; i++) {
fDataGeneratorCMs[i] = new DataGeneratorCacheManager(
immediateExecutor, generators[i]);
generators[i].addListener(this);
}
}
public void getCount(final DataRequestMonitor<Integer> rm) {
// Artificially delay the retrieval of the sum data to simulate
// real processing time.
fExecutor.schedule( new Runnable() {
public void run() {
// Create the transaction here to put all the ugly
// code in one place.
new Transaction<Integer>() {
@Override
protected Integer process()
throws Transaction.InvalidCacheException,
CoreException
{
return processCount(this);
}
}.request(rm);
}
},
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
}
/**
* Perform the calculation to get the max count for the given transaction.
* @param transaction The ACPM transaction to use for calculation.
* @return Calculated count.
* @throws Transaction.InvalidCacheException {@link Transaction#process}
* @throws CoreException See {@link Transaction#process}
*/
private Integer processCount(Transaction<Integer> transaction)
throws Transaction.InvalidCacheException, CoreException
{
// Assemble all needed count caches into a collection.
List<ICache<Integer>> countCaches =
new ArrayList<ICache<Integer>>(fDataGeneratorCMs.length);
for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
countCaches.add(dataGeneratorCM.getCount());
}
// Validate all count caches at once. This executes needed requests
// in parallel.
transaction.validate(countCaches);
// Calculate the max value and return.
int maxCount = 0;
for (ICache<Integer> countCache : countCaches) {
maxCount = Math.max(maxCount, countCache.getData());
}
return maxCount;
}
public void getValue(final int index, final DataRequestMonitor<Integer> rm)
{
// Add a processing delay.
fExecutor.schedule( new Runnable() {
public void run() {
new Transaction<Integer>() {
@Override
protected Integer process()
throws Transaction.InvalidCacheException,
CoreException
{
return processValue(this, index);
}
}.request(rm);
}
},
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
}
/**
* Perform the calculation to get the sum of values at given index.
* @param transaction The ACPM transaction to use for calculation.
* @param index Index of value to calculate.
* @return Calculated value.
* @throws Transaction.InvalidCacheException {@link Transaction#process}
* @throws CoreException See {@link Transaction#process}
*/
private Integer processValue(Transaction<Integer> transaction, int index)
throws Transaction.InvalidCacheException, CoreException
{
List<ICache<Integer>> valueCaches =
new ArrayList<ICache<Integer>>(fDataGeneratorCMs.length);
for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
valueCaches.add(dataGeneratorCM.getValue(index));
}
// Validate all value caches at once. This executes needed requests
// in parallel.
transaction.validate(valueCaches);
int sum = 0;
for (ICache<Integer> valueCache : valueCaches) {
sum += valueCache.getData();
}
return sum;
}
public void shutdown(final RequestMonitor rm) {
for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
dataGeneratorCM.getDataGenerator().removeListener(this);
dataGeneratorCM.dispose();
rm.done();
}
rm.done();
}
public void addListener(final Listener listener) {
// Must access fListeners on executor thread.
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fListeners.add(listener);
}
});
} catch (RejectedExecutionException e) {}
}
public void removeListener(final Listener listener) {
// Must access fListeners on executor thread.
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fListeners.remove(listener);
}
});
} catch (RejectedExecutionException e) {}
}
public void countChanged() {
// Must access fListeners on executor thread.
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
for (Listener listener : fListeners) {
listener.countChanged();
}
}
});
} catch (RejectedExecutionException e) {}
}
public void valuesChanged(final Set<Integer> changed) {
// Must access fListeners on executor thread.
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
for (Object listener : fListeners) {
((Listener)listener).valuesChanged(changed);
}
}
});
} catch (RejectedExecutionException e) {}
}
}

View file

@ -0,0 +1,482 @@
/*******************************************************************************
* Copyright (c) 2011 Wind River Systems 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
//#ifdef exercises
package org.eclipse.cdt.examples.dsf.dataviewer;
//#else
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
//#endif
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.ICache;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
import org.eclipse.cdt.dsf.concurrent.Transaction;
import org.eclipse.cdt.dsf.ui.concurrent.DisplayDsfExecutor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
/**
* Data viewer based on a table, which reads data from multiple data
* providers using ACPM methods and performs a computation on the
* retrieved data.
* <p>
* This example builds on the {@link AsyncSumDataViewer} example. It
* demonstrates using ACPM to solve the data consistency problem when
* retrieving data from multiple sources asynchronously.
* </p>
*/
@ConfinedToDsfExecutor("fDisplayExecutor")
public class ACPMSumDataViewer implements ILazyContentProvider
{
/** View update frequency interval. */
final private static int UPDATE_INTERVAL = 10000;
/** Executor to use instead of Display.asyncExec(). **/
@ThreadSafe
final private DsfExecutor fDisplayExecutor;
/** Executor to use when retrieving data from data providers */
@ThreadSafe
final private ImmediateInDsfExecutor fDataExecutor;
// The viewer and generator that this content provider using.
final private TableViewer fViewer;
final private DataGeneratorCacheManager[] fDataGeneratorCMs;
final private DataGeneratorCacheManager fSumGeneratorCM;
// Fields used in request cancellation logic.
private List<ValueRequestMonitor> fItemDataRequestMonitors =
new LinkedList<ValueRequestMonitor>();
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
private int fCancelCallsPending = 0;
private Future<?> fRefreshFuture;
public ACPMSumDataViewer(TableViewer viewer,
ImmediateInDsfExecutor dataExecutor, IDataGenerator[] generators,
IDataGenerator sumGenerator)
{
fViewer = viewer;
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(
fViewer.getTable().getDisplay());
fDataExecutor = dataExecutor;
// Create wrappers for data generators. Don't need to register as
// listeners to generator events because the cache managers ensure data
// are already registered for them.
fDataGeneratorCMs = new DataGeneratorCacheManager[generators.length];
for (int i = 0; i < generators.length; i++) {
fDataGeneratorCMs[i] =
new DataGeneratorCacheManager(fDataExecutor, generators[i]);
}
fSumGeneratorCM =
new DataGeneratorCacheManager(fDataExecutor, sumGenerator);
// Schedule a task to refresh the viewer periodically.
fRefreshFuture = fDisplayExecutor.scheduleAtFixedRate(
new Runnable() {
public void run() {
queryItemCount();
}
},
UPDATE_INTERVAL, UPDATE_INTERVAL, TimeUnit.MILLISECONDS);
}
public void dispose() {
// Cancel the periodic task of refreshing the view.
fRefreshFuture.cancel(false);
// Need to dispose cache managers that were created in this class. This
// needs to be done on the cache manager's thread.
Query<Object> disposeCacheManagersQuery = new Query<Object>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
fSumGeneratorCM.dispose();
for (DataGeneratorCacheManager dataGeneratorCM :
fDataGeneratorCMs)
{
dataGeneratorCM.dispose();
}
rm.setData(new Object());
rm.done();
}
};
fDataExecutor.execute(disposeCacheManagersQuery);
try {
disposeCacheManagersQuery.get();
}
catch (InterruptedException e) {}
catch (ExecutionException e) {}
// Cancel any outstanding data requests.
for (ValueRequestMonitor rm : fItemDataRequestMonitors) {
rm.cancel();
}
fItemDataRequestMonitors.clear();
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// Set the initial count to the viewer after the input is set.
queryItemCount();
}
public void updateElement(final int index) {
// Calculate the visible index range.
final int topIdx = fViewer.getTable().getTopIndex();
final int botIdx = topIdx + getVisibleItemCount(topIdx);
// Request the item for the given index.
queryValue(index);
// Invoke a cancel task with a delay. The delay allows multiple cancel
// calls to be combined together improving performance of the viewer.
fCancelCallsPending++;
fDisplayExecutor.execute(
new Runnable() { public void run() {
cancelStaleRequests(topIdx, botIdx);
}});
}
/**
* Calculates the number of visible items based on the top item index and
* table bounds.
* @param top Index of top item.
* @return calculated number of items in viewer
*/
private int getVisibleItemCount(int top) {
Table table = fViewer.getTable();
int itemCount = table.getItemCount();
return Math.min(
(table.getBounds().height / table.getItemHeight()) + 2,
itemCount - top);
}
/**
* Retrieve the current count. When a new count is set to viewer, the viewer
* will refresh all items as well.
*/
private void queryItemCount() {
// Create the request monitor to collect the count. This request
// monitor will be completed by the following transaction.
final DataRequestMonitor<Integer> rm =
new DataRequestMonitor<Integer>(fDisplayExecutor, null)
{
@Override
protected void handleSuccess() {
setCountToViewer(getData());
}
@Override
protected void handleRejectedExecutionException() {} // Shutting down, ignore.
};
// Use a transaction, even with a single cache. This will ensure that
// if the cache is reset during processing by an event. The request
// for data will be re-issued.
fDataExecutor.execute(new Runnable() {
public void run() {
new Transaction<Integer>() {
@Override
protected Integer process()
throws Transaction.InvalidCacheException, CoreException
{
return processCount(this);
}
}.request(rm);
}
});
}
/**
* Perform the count retrieval from the sum data generator.
* @param transaction The ACPM transaction to use for calculation.
* @return Calculated count.
* @throws Transaction.InvalidCacheException {@link Transaction#process}
* @throws CoreException See {@link Transaction#process}
*/
private Integer processCount(Transaction<Integer> transaction)
throws Transaction.InvalidCacheException, CoreException
{
ICache<Integer> countCache = fSumGeneratorCM.getCount();
transaction.validate(countCache);
return countCache.getData();
}
/**
* Set the givne count to the viewer. This will cause the viewer will
* refresh all items' data as well.
* <p>Note: This method must be called in the display thread. </p>
* @param count New count to set to viewer.
*/
private void setCountToViewer(int count) {
if (!fViewer.getTable().isDisposed()) {
fViewer.setItemCount(count);
fViewer.getTable().clearAll();
}
}
/**
* Retrieve the current value for given index.
*/
private void queryValue(final int index) {
// Create the request monitor to collect the value. This request
// monitor will be completed by the following transaction.
final ValueRequestMonitor rm = new ValueRequestMonitor(index) {
@Override
protected void handleCompleted() {
fItemDataRequestMonitors.remove(this);
if (isSuccess()) {
setValueToViewer(index, getData());
}
}
@Override
protected void handleRejectedExecutionException() {
// Shutting down, ignore.
}
};
// Save the value request monitor, to cancel it if the view is
// scrolled.
fItemDataRequestMonitors.add(rm);
// Use a transaction, even with a single cache. This will ensure that
// if the cache is reset during processing by an event. The request
// for data will be re-issued.
fDataExecutor.execute(new Runnable() {
public void run() {
new Transaction<String>() {
@Override
protected String process()
throws Transaction.InvalidCacheException, CoreException
{
return processValue(this, index);
}
}.request(rm);
}
});
}
/**
* Write the view value to the viewer.
* <p>Note: This method must be called in the display thread. </p>
* @param index Index of value to set.
* @param value New value.
*/
private void setValueToViewer(int index, String value) {
if (!fViewer.getTable().isDisposed()) {
fViewer.replace(value, index);
}
}
/**
* Perform the calculation compose the string with data provider values
* and the sum. This implementation also validates the result.
* @param transaction The ACPM transaction to use for calculation.
* @param index Index of value to calculate.
* @return Calculated value.
* @throws Transaction.InvalidCacheException {@link Transaction#process}
* @throws CoreException See {@link Transaction#process}
*/
private String processValue(Transaction<String> transaction, int index)
throws Transaction.InvalidCacheException, CoreException
{
List<ICache<Integer>> valueCaches =
new ArrayList<ICache<Integer>>(fDataGeneratorCMs.length);
for (DataGeneratorCacheManager dataGeneratorCM : fDataGeneratorCMs) {
valueCaches.add(dataGeneratorCM.getValue(index));
}
// Validate all value caches at once. This executes needed requests
// in parallel.
transaction.validate(valueCaches);
// TODO: evaluate sum generator cache in parallel with value caches.
ICache<Integer> sumCache = fSumGeneratorCM.getValue(index);
transaction.validate(sumCache);
// Compose the string with values, sum, and validation result.
StringBuilder result = new StringBuilder();
int calcSum = 0;
for (ICache<Integer> valueCache : valueCaches) {
if (result.length() != 0) result.append(" + ");
result.append(valueCache.getData());
calcSum += valueCache.getData();
}
result.append(" = ");
result.append(sumCache.getData());
if (calcSum != sumCache.getData()) {
result.append(" !INCORRECT! ");
}
return result.toString();
}
/**
* Dedicated class for data item requests. This class holds the index
* argument so it can be examined when canceling stale requests.
*/
private class ValueRequestMonitor extends DataRequestMonitor<String> {
/** Index is used when canceling stale requests. */
int fIndex;
ValueRequestMonitor(int index) {
super(fDisplayExecutor, null);
fIndex = index;
}
@Override
protected void handleRejectedExecutionException() {
// Shutting down, ignore.
}
}
/**
* Cancels any outstanding value requests for items which are no longer
* visible in the viewer.
*
* @param topIdx Index of top visible item in viewer.
* @param botIdx Index of bottom visible item in viewer.
*/
private void cancelStaleRequests(int topIdx, int botIdx) {
// Decrement the count of outstanding cancel calls.
fCancelCallsPending--;
// Must check again, in case disposed while re-dispatching.
if (fDataGeneratorCMs == null || fViewer.getTable().isDisposed()) {
return;
}
// Go through the outstanding requests and cancel any that
// are not visible anymore.
for (Iterator<ValueRequestMonitor> itr =
fItemDataRequestMonitors.iterator(); itr.hasNext();)
{
ValueRequestMonitor item = itr.next();
if (item.fIndex < topIdx || item.fIndex > botIdx) {
// Set the item to canceled status, so that the data provider
// will ignore it.
item.cancel();
// Add the item index to list of indexes that were canceled,
// which will be sent to the table widget.
fIndexesToCancel.add(item.fIndex);
// Remove the item from the outstanding cancel requests.
itr.remove();
}
}
if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
Set<Integer> canceledIdxs = fIndexesToCancel;
fIndexesToCancel = new HashSet<Integer>();
// Clear the indexes of the canceled request, so that the
// viewer knows to request them again when needed.
// Note: clearing using TableViewer.clear(int) seems very
// inefficient, it's better to use Table.clear(int[]).
int[] canceledIdxsArray = new int[canceledIdxs.size()];
int i = 0;
for (Integer index : canceledIdxs) {
canceledIdxsArray[i++] = index;
}
fViewer.getTable().clear(canceledIdxsArray);
}
}
/**
* The entry point for the example.
* @param args Program arguments.
*/
public static void main(String[] args) {
// Create the shell to hold the viewer.
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new GridLayout());
GridData data = new GridData(GridData.FILL_BOTH);
shell.setLayoutData(data);
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
// Create the table viewer.
TableViewer tableViewer =
new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
tableViewer.getControl().setLayoutData(data);
DsfExecutor executor = new DefaultDsfExecutor("Example executor");
// Create the data generator.
final IDataGenerator[] generators = new IDataGenerator[5];
for (int i = 0; i < generators.length; i++) {
generators[i] = new DataGeneratorWithExecutor(executor);
}
final IDataGenerator sumGenerator =
new ACPMSumDataGenerator(executor, generators);
// Create the content provider which will populate the viewer.
ACPMSumDataViewer contentProvider = new ACPMSumDataViewer(
tableViewer, new ImmediateInDsfExecutor(executor),
generators, sumGenerator);
tableViewer.setContentProvider(contentProvider);
tableViewer.setInput(new Object());
// Open the shell and service the display dispatch loop until user
// closes the shell.
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// The IDataGenerator.shutdown() method is asynchronous, this requires
// using a query again in order to wait for its completion.
Query<Object> shutdownQuery = new Query<Object>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
CountingRequestMonitor crm = new CountingRequestMonitor(
ImmediateExecutor.getInstance(), rm);
for (int i = 0; i < generators.length; i++) {
generators[i].shutdown(crm);
}
sumGenerator.shutdown(crm);
crm.setDoneCount(generators.length);
}
};
executor.execute(shutdownQuery);
try {
shutdownQuery.get();
} catch (Exception e) {}
// Shut down the display.
font.dispose();
display.dispose();
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2009 Wind River Systems and others.
* Copyright (c) 2006, 2011 Wind River Systems 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
@ -66,13 +66,15 @@ public class AsyncDataViewer
final private IDataGenerator fDataGenerator;
// Fields used in request cancellation logic.
private List<ValueDataRequestMonitor> fItemDataRequestMonitors = new LinkedList<ValueDataRequestMonitor>();
private List<ValueDataRequestMonitor> fItemDataRequestMonitors =
new LinkedList<ValueDataRequestMonitor>();
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
private int fCancelCallsPending = 0;
public AsyncDataViewer(TableViewer viewer, IDataGenerator generator) {
fViewer = viewer;
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(fViewer.getTable().getDisplay());
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(
fViewer.getTable().getDisplay());
fDataGenerator = generator;
fDataGenerator.addListener(this);
}
@ -104,10 +106,18 @@ public class AsyncDataViewer
1, TimeUnit.MILLISECONDS);
}
/**
* Calculates the number of visible items based on the top item index and
* table bounds.
* @param top Index of top item.
* @return calculated number of items in viewer
*/
private int getVisibleItemCount(int top) {
Table table = fViewer.getTable();
int itemCount = table.getItemCount();
return Math.min((table.getBounds().height / table.getItemHeight()) + 2, itemCount - top);
return Math.min(
(table.getBounds().height / table.getItemHeight()) + 2,
itemCount - top);
}
@ThreadSafe
@ -131,7 +141,10 @@ public class AsyncDataViewer
}});
}
/**
* Retrieve the up to date count. When a new count is set to viewer, the
* viewer will refresh all items as well.
*/
private void queryItemCount() {
// Request count from data provider. When the count is returned, we
// have to re-dispatch into the display thread to avoid calling
@ -150,13 +163,25 @@ public class AsyncDataViewer
}
}
});
}
// Dedicated class for data item requests. This class holds the index
// argument so it can be examined when canceling stale requests.
private class ValueDataRequestMonitor extends DataRequestMonitor<String> {
/**
* Retrieves value of an element at given index. When complete the value
* is written to the viewer.
* @param index Index of value to retrieve.
*/
private void queryValue(final int index) {
ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
fItemDataRequestMonitors.add(rm);
fDataGenerator.getValue(index, rm);
}
/**
* Dedicated class for data item requests. This class holds the index
* argument so it can be examined when canceling stale requests.
*/
private class ValueDataRequestMonitor extends DataRequestMonitor<Integer> {
/** Index is used when canceling stale requests. */
int fIndex;
@ -170,7 +195,8 @@ public class AsyncDataViewer
protected void handleCompleted() {
fItemDataRequestMonitors.remove(this);
// Check if the request completed successfully, otherwise ignore it.
// Check if the request completed successfully, otherwise ignore
// it.
if (isSuccess()) {
if (!fViewer.getTable().isDisposed()) {
fViewer.replace(getData(), fIndex);
@ -179,12 +205,6 @@ public class AsyncDataViewer
}
}
private void queryValue(final int index) {
ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
fItemDataRequestMonitors.add(rm);
fDataGenerator.getValue(index, rm);
}
private void cancelStaleRequests(int topIdx, int botIdx) {
// Decrement the count of outstanding cancel calls.
fCancelCallsPending--;
@ -194,7 +214,10 @@ public class AsyncDataViewer
// Go through the outstanding requests and cancel any that
// are not visible anymore.
for (Iterator<ValueDataRequestMonitor> itr = fItemDataRequestMonitors.iterator(); itr.hasNext();) {
for (Iterator<ValueDataRequestMonitor> itr =
fItemDataRequestMonitors.iterator();
itr.hasNext();)
{
ValueDataRequestMonitor item = itr.next();
if (item.fIndex < topIdx || item.fIndex > botIdx) {
// Set the item to canceled status, so that the data provider
@ -237,14 +260,16 @@ public class AsyncDataViewer
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
// Create the table viewer.
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
TableViewer tableViewer =
new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
tableViewer.getControl().setLayoutData(data);
// Create the data generator.
final IDataGenerator generator = new DataGeneratorWithExecutor();
// Create the content provider which will populate the viewer.
AsyncDataViewer contentProvider = new AsyncDataViewer(tableViewer, generator);
AsyncDataViewer contentProvider =
new AsyncDataViewer(tableViewer, generator);
tableViewer.setContentProvider(contentProvider);
tableViewer.setInput(new Object());

View file

@ -0,0 +1,171 @@
/*******************************************************************************
* Copyright (c) 2011 Wind River Systems 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
//#ifdef exercises
package org.eclipse.cdt.examples.dsf.dataviewer;
//#else
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
//#endif
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
/**
* A data generator which performs a sum computation on data retrieved from a
* number of other data generators. The data retrieval from other generators
* is performed in parallel and the result is calculated once all data is
* received.
* <p>
* This calculating generator does not listen to events from the data
* providers so it relies on the client to re-retrieve data as needed.
* </p>
*/
public class AsyncSumDataGenerator implements IDataGenerator {
/**
* DSF executor used to serialize data access within this data generator.
*/
final private DsfExecutor fExecutor;
/**
* Data generators to retrieve original data to perform calculations on.
*/
final private IDataGenerator[] fDataGenerators;
public AsyncSumDataGenerator(DsfExecutor executor,
IDataGenerator[] generators)
{
fExecutor = executor;
fDataGenerators = generators;
}
public void getCount(final DataRequestMonitor<Integer> rm) {
// Artificially delay the retrieval of the sum data to simulate
// real processing time.
fExecutor.schedule( new Runnable() {
public void run() {
doGetCount(rm);
}
},
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
}
/**
* Performs the actual count retrieval and calculation.
* @param rm Request monitor to complete with data.
*/
private void doGetCount(final DataRequestMonitor<Integer> rm) {
// Array to store counts retrieved asynchronously
final int[] counts = new int[fDataGenerators.length];
// Counting request monitor is called once all data is retrieved.
final CountingRequestMonitor crm =
new CountingRequestMonitor(fExecutor, rm)
{
@Override
protected void handleSuccess() {
// Pick the highest count value.
Arrays.sort(counts, 0, counts.length - 1);
int maxCount = counts[counts.length - 1];
rm.setData(maxCount);
rm.done();
};
};
// Each call to data generator fills in one value in array.
for (int i = 0; i < fDataGenerators.length; i++) {
final int finalI = i;
fDataGenerators[i].getCount(
new DataRequestMonitor<Integer>(
ImmediateExecutor.getInstance(), crm)
{
@Override
protected void handleSuccess() {
counts[finalI] = getData();
crm.done();
}
});
}
crm.setDoneCount(fDataGenerators.length);
}
public void getValue(final int index, final DataRequestMonitor<Integer> rm)
{
// Artificially delay the retrieval of the sum data to simulate
// real processing time.
fExecutor.schedule( new Runnable() {
public void run() {
doGetValue(index, rm);
}
},
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
}
/**
* Performs the actual value retrieval and calculation.
* @param rm Request monitor to complete with data.
*/
private void doGetValue(int index, final DataRequestMonitor<Integer> rm) {
// Array to store counts retrieved asynchronously
final int[] values = new int[fDataGenerators.length];
// Counting request monitor is called once all data is retrieved.
final CountingRequestMonitor crm =
new CountingRequestMonitor(fExecutor, rm)
{
@Override
protected void handleSuccess() {
// Sum up values in array.
int sum = 0;
for (int value : values) {
sum += value;
}
rm.setData(sum);
rm.done();
};
};
// Each call to data generator fills in one value in array.
for (int i = 0; i < fDataGenerators.length; i++) {
final int finalI = i;
fDataGenerators[i].getValue(
index,
new DataRequestMonitor<Integer>(
ImmediateExecutor.getInstance(), crm)
{
@Override
protected void handleSuccess() {
values[finalI] = getData();
crm.done();
}
});
}
crm.setDoneCount(fDataGenerators.length);
}
public void shutdown(RequestMonitor rm) {
rm.done();
}
public void addListener(final Listener listener) {
// no events generated
}
public void removeListener(Listener listener) {
// no events generated
}
}

View file

@ -0,0 +1,410 @@
/*******************************************************************************
* Copyright (c) 2011 Wind River Systems 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
//#ifdef exercises
package org.eclipse.cdt.examples.dsf.dataviewer;
//#else
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
//#endif
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
import org.eclipse.cdt.dsf.ui.concurrent.DisplayDsfExecutor;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
/**
* Data viewer based on a table, which reads data from multiple data
* providers using asynchronous methods and performs a compultation
* on the retrieved data.
* <p>
* This example builds on the {@link AsyncDataViewer} example and
* demonstrates the pitfalls of retrieving data from multiple sources
* asynchronously: The data is retrieved separate from a set of providers
* as well as from a data provider that sums the values from the other
* providers. The viewer then performs a check to ensure consistency of
* retrieved data. If the retrieved data is inconsistent an "INCORRECT"
* label is added in the viewer.
* </p>
* <p>
* This viewer is updated periodically every 10 seconds, instead of being
* updated with every change in every data provider, which would overwhelm
* the viewer.
* </p>
*/
@ConfinedToDsfExecutor("fDisplayExecutor")
public class AsyncSumDataViewer implements ILazyContentProvider
{
/** View update frequency interval. */
final private static int UPDATE_INTERVAL = 10000;
/** Executor to use instead of Display.asyncExec(). **/
@ThreadSafe
final private DsfExecutor fDisplayExecutor;
// The viewer and generator that this content provider using.
final private TableViewer fViewer;
final private IDataGenerator[] fDataGenerators;
final private IDataGenerator fSumGenerator;
// Fields used in request cancellation logic.
private List<ValueCountingRequestMonitor> fItemDataRequestMonitors =
new LinkedList<ValueCountingRequestMonitor>();
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
private int fCancelCallsPending = 0;
private Future<?> fRefreshFuture;
public AsyncSumDataViewer(TableViewer viewer,
IDataGenerator[] generators, IDataGenerator sumGenerator)
{
fViewer = viewer;
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(
fViewer.getTable().getDisplay());
fDataGenerators = generators;
fSumGenerator = sumGenerator;
// Schedule a task to refresh the viewer periodically.
fRefreshFuture = fDisplayExecutor.scheduleAtFixedRate(
new Runnable() {
public void run() {
queryItemCount();
}
},
UPDATE_INTERVAL, UPDATE_INTERVAL, TimeUnit.MILLISECONDS);
}
public void dispose() {
// Cancel the periodic task of refreshing the view.
fRefreshFuture.cancel(false);
// Cancel any outstanding data requests.
for (ValueCountingRequestMonitor rm : fItemDataRequestMonitors) {
rm.cancel();
}
fItemDataRequestMonitors.clear();
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// Set the initial count to the viewer after the input is set.
queryItemCount();
}
public void updateElement(final int index) {
// Calculate the visible index range.
final int topIdx = fViewer.getTable().getTopIndex();
final int botIdx = topIdx + getVisibleItemCount(topIdx);
// Request the item for the given index.
queryValue(index);
// Invoke a cancel task with a delay. The delay allows multiple cancel
// calls to be combined together improving performance of the viewer.
fCancelCallsPending++;
fDisplayExecutor.execute(
new Runnable() { public void run() {
cancelStaleRequests(topIdx, botIdx);
}});
}
/**
* Calculates the number of visible items based on the top item index and
* table bounds.
* @param top Index of top item.
* @return calculated number of items in viewer
*/
private int getVisibleItemCount(int top) {
Table table = fViewer.getTable();
int itemCount = table.getItemCount();
return Math.min(
(table.getBounds().height / table.getItemHeight()) + 2,
itemCount - top);
}
/**
* Retrieve the up to date count.
*/
private void queryItemCount() {
// Note:The count is retrieved from the sum generator only, the sum
// generator is responsible for calculating the count based on
// individual data providers' counts.
fIndexesToCancel.clear();
fSumGenerator.getCount(
new DataRequestMonitor<Integer>(fDisplayExecutor, null) {
@Override
protected void handleSuccess() {
setCountToViewer(getData());
}
@Override
protected void handleRejectedExecutionException() {
// Shutting down, ignore.
}
});
}
/**
* Set the givne count to the viewer. This will cause the viewer will
* refresh all items' data as well.
* @param count New count to set to viewer.
*/
private void setCountToViewer(int count) {
if (!fViewer.getTable().isDisposed()) {
fViewer.setItemCount(count);
fViewer.getTable().clearAll();
}
}
/**
* Retrieves value of an element at given index. When complete the value
* is written to the viewer.
* @param index Index of value to retrieve.
*/
private void queryValue(final int index) {
// Values retrieved asynchronously from providers are stored in local
// arrays.
final int[] values = new int[fDataGenerators.length];
final int[] sum = new int[1];
// Counting request monitor is invoked when the required number of
// value requests is completed.
final ValueCountingRequestMonitor crm =
new ValueCountingRequestMonitor(index)
{
@Override
protected void handleCompleted() {
fItemDataRequestMonitors.remove(this);
// Check if the request completed successfully, otherwise
// ignore it.
if (isSuccess()) {
StringBuilder result = new StringBuilder();
int calcSum = 0;
for (int value : values) {
if (result.length() != 0) result.append(" + ");
result.append(value);
calcSum += value;
}
result.append(" = ");
result.append(sum[0]);
if (calcSum != sum[0]) {
result.append(" !INCORRECT! ");
}
setValueToViewer(fIndex, result.toString());
}
};
};
// Request data from each data generator.
for (int i = 0; i < fDataGenerators.length; i++) {
final int finalI = i;
fDataGenerators[i].getValue(
index,
// Use the display executor to construct the request monitor,
// this will cause the handleCompleted() method to be
// automatically called on the display thread.
new DataRequestMonitor<Integer>(
ImmediateExecutor.getInstance(), crm)
{
@Override
protected void handleSuccess() {
values[finalI] = getData();
crm.done();
}
});
}
// Separately request data from the sum data generator.
fSumGenerator.getValue(
index,
new DataRequestMonitor<Integer>(
ImmediateExecutor.getInstance(), crm)
{
@Override
protected void handleSuccess() {
sum[0] = getData();
crm.done();
}
});
crm.setDoneCount(fDataGenerators.length + 1);
fItemDataRequestMonitors.add(crm);
}
/**
* Write the view value to the viewer.
* <p>Note: This method must be called in the display thread. </p>
* @param index Index of value to set.
* @param value New value.
*/
private void setValueToViewer(int index, String value) {
if (!fViewer.getTable().isDisposed()) {
fViewer.replace(value, index);
}
}
/**
* Dedicated class for data item requests. This class holds the index
* argument so it can be examined when canceling stale requests.
*/
private class ValueCountingRequestMonitor extends CountingRequestMonitor {
/** Index is used when canceling stale requests. */
int fIndex;
ValueCountingRequestMonitor(int index) {
super(fDisplayExecutor, null);
fIndex = index;
}
@Override
protected void handleRejectedExecutionException() {
// Shutting down, ignore.
}
}
/**
* Cancels any outstanding value requests for items which are no longer
* visible in the viewer.
*
* @param topIdx Index of top visible item in viewer.
* @param botIdx Index of bottom visible item in viewer.
*/
private void cancelStaleRequests(int topIdx, int botIdx) {
// Decrement the count of outstanding cancel calls.
fCancelCallsPending--;
// Must check again, in case disposed while re-dispatching.
if (fDataGenerators == null || fViewer.getTable().isDisposed()) return;
// Go through the outstanding requests and cancel any that
// are not visible anymore.
for (Iterator<ValueCountingRequestMonitor> itr =
fItemDataRequestMonitors.iterator(); itr.hasNext();)
{
ValueCountingRequestMonitor item = itr.next();
if (item.fIndex < topIdx || item.fIndex > botIdx) {
// Set the item to canceled status, so that the data provider
// will ignore it.
item.cancel();
// Add the item index to list of indexes that were canceled,
// which will be sent to the table widget.
fIndexesToCancel.add(item.fIndex);
// Remove the item from the outstanding cancel requests.
itr.remove();
}
}
if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
Set<Integer> canceledIdxs = fIndexesToCancel;
fIndexesToCancel = new HashSet<Integer>();
// Clear the indexes of the canceled request, so that the
// viewer knows to request them again when needed.
// Note: clearing using TableViewer.clear(int) seems very
// inefficient, it's better to use Table.clear(int[]).
int[] canceledIdxsArray = new int[canceledIdxs.size()];
int i = 0;
for (Integer index : canceledIdxs) {
canceledIdxsArray[i++] = index;
}
fViewer.getTable().clear(canceledIdxsArray);
}
}
/**
* The entry point for the example.
* @param args Program arguments.
*/
public static void main(String[] args) {
// Create the shell to hold the viewer.
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new GridLayout());
GridData data = new GridData(GridData.FILL_BOTH);
shell.setLayoutData(data);
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
// Create the table viewer.
TableViewer tableViewer =
new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
tableViewer.getControl().setLayoutData(data);
// Single executor (and single thread) is used by all data generators,
// including the sum generator.
DsfExecutor executor = new DefaultDsfExecutor("Example executor");
// Create the data generator.
final IDataGenerator[] generators = new IDataGenerator[5];
for (int i = 0; i < generators.length; i++) {
generators[i] = new DataGeneratorWithExecutor(executor);
}
final IDataGenerator sumGenerator =
new AsyncSumDataGenerator(executor, generators);
// Create the content provider which will populate the viewer.
AsyncSumDataViewer contentProvider =
new AsyncSumDataViewer(tableViewer, generators, sumGenerator);
tableViewer.setContentProvider(contentProvider);
tableViewer.setInput(new Object());
// Open the shell and service the display dispatch loop until user
// closes the shell.
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// The IDataGenerator.shutdown() method is asynchronous, this requires
// using a query again in order to wait for its completion.
Query<Object> shutdownQuery = new Query<Object>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
CountingRequestMonitor crm = new CountingRequestMonitor(
ImmediateExecutor.getInstance(), rm);
for (int i = 0; i < generators.length; i++) {
generators[i].shutdown(crm);
}
sumGenerator.shutdown(crm);
crm.setDoneCount(generators.length);
}
};
executor.execute(shutdownQuery);
try {
shutdownQuery.get();
} catch (Exception e) {}
// Shut down the display.
font.dispose();
display.dispose();
}
}

View file

@ -0,0 +1,165 @@
/*******************************************************************************
* Copyright (c) 2011 Wind River Systems 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
//#ifdef exercises
package org.eclipse.cdt.examples.dsf.dataviewer;
//#else
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
//#endif
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ICache;
import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestCache;
import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
/**
* A wrapper class for the {@link IDataGenerator} interface, which returns
* ACPM cache objects to use for data retrieval instead of calling
* {@link IDataGenerator} asynchronous methods directly.
*/
public class DataGeneratorCacheManager implements IDataGenerator.Listener {
/** Cache class for retrieving the data generator's count. */
private class CountCache extends RequestCache<Integer> {
public CountCache() {
super(fExecutor);
}
@Override
protected void retrieve(DataRequestMonitor<Integer> rm) {
fDataGenerator.getCount(rm);
}
/**
* Reset the cache when the count is changed.
*/
public void countChanged() {
// Make sure that if clients are currently waiting for a count,
// they are notified of the update (their request monitors will be
// completed with an error). They shoudl then re-request data
// from provider again.
setAndReset(null, new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Count changed"));
}
}
/** Cache class for retrieving the data generator's values. */
private class ValueCache extends RequestCache<Integer> {
private int fIndex;
public ValueCache(int index) {
super(fExecutor);
fIndex = index;
}
@Override
protected void retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor<Integer> rm) {
fDataGenerator.getValue(fIndex, rm);
};
/**
* @see CountCache#countChanged()
*/
public void valueChanged() {
setAndReset(null, new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Value changed"));
}
}
/**
* Executor used to synchronize data access in this cache manager.
* It has to be the same executor that is used by the data generators in
* order to guarantee data consistency.
*/
private ImmediateInDsfExecutor fExecutor;
/**
* Data generator that this cache manager is a wrapper for.
*/
private IDataGenerator fDataGenerator;
/** Cache for data generator's count */
private CountCache fCountCache;
/**
* Map of caches for retrieving values. Each value index has a separate
* cache value object.
*/
private Map<Integer, ValueCache> fValueCaches = new HashMap<Integer, ValueCache>();
public DataGeneratorCacheManager(ImmediateInDsfExecutor executor, IDataGenerator dataGenerator) {
fExecutor = executor;
fDataGenerator = dataGenerator;
fDataGenerator.addListener(this);
}
public void dispose() {
fDataGenerator.removeListener(this);
}
/**
* Returns the data generator that this cache manager wraps.
*/
public IDataGenerator getDataGenerator() {
return fDataGenerator;
}
/**
* Returns the cache for data generator count.
*/
public ICache<Integer> getCount() {
if (fCountCache == null) {
fCountCache = new CountCache();
}
return fCountCache;
}
/**
* Returns the cache for a value at given index.
*
* @param index Index of value to return.
* @return Cache object for given value.
*/
public ICache<Integer> getValue(int index) {
ValueCache value = fValueCaches.get(index);
if (value == null) {
value = new ValueCache(index);
fValueCaches.put(index, value);
}
return value;
}
public void countChanged() {
// Reset the count cache and all the value caches.
if (fCountCache != null) {
fCountCache.countChanged();
}
for (ValueCache value : fValueCaches.values()) {
value.valueChanged();
}
}
public void valuesChanged(Set<Integer> indexes) {
// Reset selected value caches.
for (Integer index : indexes) {
ValueCache value = fValueCaches.get(index);
if (value != null) {
value.valueChanged();
}
}
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2009 Wind River Systems and others.
* Copyright (c) 2006, 2011 Wind River Systems 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
@ -14,14 +14,14 @@ package org.eclipse.cdt.examples.dsf.dataviewer;
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
//#endif
import java.util.HashSet;
import java.util.HashMap;
//#ifdef answers
//#import java.util.Iterator;
//#endif
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
@ -70,6 +70,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
Request(RequestMonitor rm) {
fRequestMonitor = rm;
rm.addCancelListener(new RequestMonitor.ICanceledListener() {
public void requestCanceled(RequestMonitor rm) {
fExecutor.execute(new DsfRunnable() {
public void run() {
fQueue.remove(Request.this);
}
});
}
});
}
}
@ -93,7 +103,7 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
//#endif
class ItemRequest extends Request {
final int fIndex;
ItemRequest(int index, DataRequestMonitor<String> rm) {
ItemRequest(int index, DataRequestMonitor<Integer> rm) {
super(rm);
fIndex = index;
}
@ -156,24 +166,20 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
//#else
//# @ConfinedToDsfExecutor("fExecutor")
//#endif
private Set<Integer> fChangedIndexes = new HashSet<Integer>();
private Map<Integer, Integer> fChangedValues =
new HashMap<Integer, Integer>();
// Flag used to ensure that requests are processed sequentially.
//#ifdef exercises
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
//#else
//# @ConfinedToDsfExecutor("fExecutor")
//#endif
private boolean fServiceQueueInProgress = false;
//#ifdef exercises
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
//#endif
public DataGeneratorWithExecutor() {
// Create the executor
fExecutor = new DefaultDsfExecutor("Supplier Executor");
this(new DefaultDsfExecutor("Supplier Executor"));
}
//#ifdef exercises
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
//#endif
public DataGeneratorWithExecutor(DsfExecutor executor) {
// Create the executor
fExecutor = executor;
// Schedule a runnable to make the random changes.
fExecutor.scheduleAtFixedRate(
@ -182,8 +188,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
randomChanges();
}
},
RANDOM_CHANGE_INTERVAL,
RANDOM_CHANGE_INTERVAL,
new Random().nextInt() % RANDOM_CHANGE_INTERVAL,
RANDOM_CHANGE_INTERVAL, //Add a 10% variance to the interval.
TimeUnit.MILLISECONDS);
}
@ -197,8 +203,9 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
public void run() {
// Empty the queue of requests and fail them.
for (Request request : fQueue) {
request.fRequestMonitor.setStatus(
new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
request.fRequestMonitor.setStatus(new Status(
IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
"Supplier shut down"));
request.fRequestMonitor.done();
}
fQueue.clear();
@ -209,7 +216,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
"Supplier shut down"));
rm.done();
}
}
@ -227,7 +235,9 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.setStatus(new Status(
IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
"Supplier shut down"));
rm.done();
}
}
@ -236,7 +246,7 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
//#endif
public void getValue(final int index, final DataRequestMonitor<String> rm) {
public void getValue(final int index, final DataRequestMonitor<Integer> rm) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
@ -245,7 +255,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
"Supplier shut down"));
rm.done();
}
}
@ -286,7 +297,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
//# @ConfinedToDsfExecutor("fExecutor")
//#endif
private void serviceQueue() {
fExecutor.schedule(
new DsfRunnable() {
public void run() {
doServiceQueue();
}
},
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
}
private void doServiceQueue() {
//#ifdef exercises
// TODO Exercise 3 - Add logic to discard cancelled requests from queue.
// Hint: Since serviceQueue() is called using the executor, and the
@ -305,33 +325,16 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
//# }
//#endif
// If a queue servicing is already scheduled, do nothing.
if (fServiceQueueInProgress) {
return;
}
if (fQueue.size() != 0) {
while (fQueue.size() != 0) {
// If there are requests to service, remove one from the queue and
// schedule a runnable to process the request after a processing
// delay.
fServiceQueueInProgress = true;
final Request request = fQueue.remove(0);
fExecutor.schedule(
new DsfRunnable() {
public void run() {
Request request = fQueue.remove(0);
if (request instanceof CountRequest) {
processCountRequest((CountRequest)request);
} else if (request instanceof ItemRequest) {
processItemRequest((ItemRequest)request);
}
// Reset the processing flag and process next
// request.
fServiceQueueInProgress = false;
serviceQueue();
}
},
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
}
}
@ -343,7 +346,8 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
//#endif
private void processCountRequest(CountRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
DataRequestMonitor<Integer> rm =
(DataRequestMonitor<Integer>)request.fRequestMonitor;
rm.setData(fCount);
rm.done();
@ -357,12 +361,13 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
//#endif
private void processItemRequest(ItemRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
DataRequestMonitor<Integer> rm =
(DataRequestMonitor<Integer>)request.fRequestMonitor;
if (fChangedIndexes.contains(request.fIndex)) {
rm.setData("Changed: " + request.fIndex);
if (fChangedValues.containsKey(request.fIndex)) {
rm.setData(fChangedValues.get(request.fIndex));
} else {
rm.setData(Integer.toString(request.fIndex));
rm.setData(request.fIndex);
}
rm.done();
}
@ -398,10 +403,11 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
private void randomCountReset() {
// Calculate the new count.
Random random = new java.util.Random();
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
fCount = MIN_COUNT +
Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
// Reset the changed values.
fChangedIndexes.clear();
fChangedValues.clear();
// Notify listeners
for (Listener listener : fListeners) {
@ -421,17 +427,19 @@ public class DataGeneratorWithExecutor implements IDataGenerator {
private void randomDataChange() {
// Calculate the indexes to change.
Random random = new java.util.Random();
Set<Integer> set = new HashSet<Integer>();
Map<Integer, Integer> changed = new HashMap<Integer, Integer>();
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
int randomIndex = Math.abs(random.nextInt()) % fCount;
int randomValue = Math.abs(random.nextInt()) % fCount;
changed.put(randomIndex, randomValue);
}
// Add the indexes to an overall set of changed indexes.
fChangedIndexes.addAll(set);
fChangedValues.putAll(changed);
// Notify listeners
for (Listener listener : fListeners) {
listener.valuesChanged(set);
for (Object listener : fListeners) {
((Listener)listener).valuesChanged(changed.keySet());
}
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2009 Wind River Systems and others.
* Copyright (c) 2006, 2011 Wind River Systems 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
@ -15,9 +15,9 @@ package org.eclipse.cdt.examples.dsf.dataviewer;
//#endif
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Random;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@ -41,7 +41,9 @@ import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
* synchronization.
* </p>
*/
public class DataGeneratorWithThread extends Thread implements IDataGenerator {
public class DataGeneratorWithThread extends Thread
implements IDataGenerator
{
// Request objects are used to serialize the interface calls into objects
// which can then be pushed into a queue.
@ -61,7 +63,7 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
class ItemRequest extends Request {
final int fIndex;
ItemRequest(int index, DataRequestMonitor<String> rm) {
ItemRequest(int index, DataRequestMonitor<Integer> rm) {
super(rm);
fIndex = index;
}
@ -76,7 +78,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
// Main request queue of the data generator. The getValue(), getCount(),
// and shutdown() methods write into the queue, while the run() method
// reads from it.
private final BlockingQueue<Request> fQueue = new LinkedBlockingQueue<Request>();
private final BlockingQueue<Request> fQueue =
new LinkedBlockingQueue<Request>();
// ListenerList class provides thread safety.
private ListenerList fListeners = new ListenerList();
@ -88,7 +91,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
private int fCountResetTrigger = 0;
// Elements which were modified since the last reset.
private Set<Integer> fChangedIndexes = Collections.synchronizedSet(new HashSet<Integer>());
private Map<Integer, Integer> fChangedValues =
Collections.synchronizedMap(new HashMap<Integer, Integer>());
// Used to determine when to make changes in data.
private long fLastChangeTime = System.currentTimeMillis();
@ -108,7 +112,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
fQueue.add(new ShutdownRequest(rm));
} else {
//
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
"Supplier shut down"));
rm.done();
}
}
@ -117,16 +122,18 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
if (!fShutdown.get()) {
fQueue.add(new CountRequest(rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
"Supplier shut down"));
rm.done();
}
}
public void getValue(int index, DataRequestMonitor<String> rm) {
public void getValue(int index, DataRequestMonitor<Integer> rm) {
if (!fShutdown.get()) {
fQueue.add(new ItemRequest(index, rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
"Supplier shut down"));
rm.done();
}
}
@ -150,7 +157,6 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
// If a request was dequeued, process it.
if (request != null) {
// Simulate a processing delay.
Thread.sleep(PROCESSING_DELAY);
if (request instanceof CountRequest) {
processCountRequest((CountRequest)request);
@ -162,6 +168,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
request.fRequestMonitor.done();
break;
}
} else {
Thread.sleep(PROCESSING_DELAY);
}
// Simulate data changes.
@ -173,7 +181,8 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
private void processCountRequest(CountRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
DataRequestMonitor<Integer> rm =
(DataRequestMonitor<Integer>)request.fRequestMonitor;
rm.setData(fCount);
rm.done();
@ -181,12 +190,13 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
private void processItemRequest(ItemRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
DataRequestMonitor<Integer> rm =
(DataRequestMonitor<Integer>)request.fRequestMonitor;
if (fChangedIndexes.contains(request.fIndex)) {
rm.setData("Changed: " + request.fIndex);
if (fChangedValues.containsKey(request.fIndex)) {
rm.setData(fChangedValues.get(request.fIndex));
} else {
rm.setData(Integer.toString(request.fIndex));
rm.setData(request.fIndex);
}
rm.done();
}
@ -194,7 +204,9 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
private void randomChanges() {
// Check if enough time is elapsed.
if (System.currentTimeMillis() > fLastChangeTime + RANDOM_CHANGE_INTERVAL) {
if (System.currentTimeMillis() >
fLastChangeTime + RANDOM_CHANGE_INTERVAL)
{
fLastChangeTime = System.currentTimeMillis();
// Once every number of changes, reset the count, the rest of the
@ -213,7 +225,7 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
// Reset the changed values.
fChangedIndexes.clear();
fChangedValues.clear();
// Notify listeners
for (Object listener : fListeners.getListeners()) {
@ -224,17 +236,19 @@ public class DataGeneratorWithThread extends Thread implements IDataGenerator {
private void randomDataChange() {
// Calculate the indexes to change.
Random random = new java.util.Random();
Set<Integer> set = new HashSet<Integer>();
Map<Integer, Integer> changed = new HashMap<Integer, Integer>();
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
int randomIndex = Math.abs(random.nextInt()) % fCount;
int randomValue = Math.abs(random.nextInt()) % fCount;
changed.put(randomIndex, randomValue);
}
// Add the indexes to an overall set of changed indexes.
fChangedIndexes.addAll(set);
fChangedValues.putAll(changed);
// Notify listeners
for (Object listener : fListeners.getListeners()) {
((Listener)listener).valuesChanged(set);
((Listener)listener).valuesChanged(changed.keySet());
}
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2009 Wind River Systems and others.
* Copyright (c) 2006, 2011 Wind River Systems 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
@ -41,11 +41,11 @@ public interface IDataGenerator {
// Changing the count range can stress the scalability of the system, while
// changing of the process delay and random change interval can stress
// its performance.
final static int MIN_COUNT = 100;
final static int MAX_COUNT = 200;
final static int PROCESSING_DELAY = 10;
final static int RANDOM_CHANGE_INTERVAL = 10000;
final static int RANDOM_COUNT_CHANGE_INTERVALS = 3;
final static int MIN_COUNT = 50;
final static int MAX_COUNT = 100;
final static int PROCESSING_DELAY = 500;
final static int RANDOM_CHANGE_INTERVAL = 4000;
final static int RANDOM_COUNT_CHANGE_INTERVALS = 5;
final static int RANDOM_CHANGE_SET_PERCENTAGE = 10;
@ -58,7 +58,7 @@ public interface IDataGenerator {
// Data access methods.
void getCount(DataRequestMonitor<Integer> rm);
void getValue(int index, DataRequestMonitor<String> rm);
void getValue(int index, DataRequestMonitor<Integer> rm);
// Method used to shutdown the data generator including any threads that
// it may use.

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2009 Wind River Systems and others.
* Copyright (c) 2008, 2011 Wind River Systems 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
@ -14,8 +14,11 @@ package org.eclipse.cdt.examples.dsf.dataviewer;
//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
//#endif
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.Query;
@ -35,8 +38,8 @@ import org.eclipse.swt.widgets.Shell;
* This viewer implements the {@link IStructuredContentProvider} interface
* which is used by the JFace TableViewer class to populate a Table. This
* interface contains one principal methods for reading data {@link #getElements(Object)},
* which synchronously returns an array of elements. In order to implement this
* method using the asynchronous data generator, this provider uses the
* which synchronously returns an array of elements. In order to implement
* this method using the asynchronous data generator, this provider uses the
* {@link Query} object.
* </p>
*/
@ -84,27 +87,43 @@ public class SyncDataViewer
return new Object[0];
}
// Create the array that will be filled with elements.
// For each index in the array execute a query to get the element at
// that index.
final Object[] elements = new Object[count];
for (int i = 0; i < count; i++) {
final int index = i;
Query<String> valueQuery = new Query<String>() {
final int finalCount = count;
Query<List<Integer>> valueQuery = new Query<List<Integer>>() {
@Override
protected void execute(DataRequestMonitor<String> rm) {
fDataGenerator.getValue(index, rm);
protected void execute(final DataRequestMonitor<List<Integer>> rm) {
final Integer[] retVal = new Integer[finalCount];
final CountingRequestMonitor crm = new CountingRequestMonitor(
ImmediateExecutor.getInstance(), rm)
{
@Override
protected void handleSuccess() {
rm.setData(Arrays.asList(retVal));
rm.done();
};
};
for (int i = 0; i < finalCount; i++) {
final int finalI = i;
fDataGenerator.getValue(
i,
new DataRequestMonitor<Integer>(
ImmediateExecutor.getInstance(), crm)
{
@Override
protected void handleSuccess() {
retVal[finalI] = getData();
crm.done();
}
});
}
crm.setDoneCount(finalCount);
}
};
ImmediateExecutor.getInstance().execute(valueQuery);
try {
elements[i] = valueQuery.get();
return valueQuery.get().toArray(new Integer[0]);
} catch (Exception e) {
elements[i] = "error";
}
}
return elements;
return new Object[0];
}
public void dispose() {
@ -140,6 +159,10 @@ public class SyncDataViewer
});
}
/**
* The entry point for the example.
* @param args Program arguments.
*/
public static void main(String[] args) {
// Create the shell to hold the viewer.
Display display = new Display();
@ -162,7 +185,8 @@ public class SyncDataViewer
//#endif
// Create the content provider which will populate the viewer.
SyncDataViewer contentProvider = new SyncDataViewer(tableViewer, generator);
SyncDataViewer contentProvider =
new SyncDataViewer(tableViewer, generator);
tableViewer.setContentProvider(contentProvider);
tableViewer.setInput(new Object());